Life of A Pixel
Life of A Pixel
Steve Kobes
[email protected]
Nov 2020
slides: bit.ly/lifeofapixel
with special thanks to past presenters "The unexamined pixel is not worth rendering."
dknox@, chrishtr@, pdr@ — Socrates
LIFE OF A
88.0.4307.0
(Nov 2020)
LIFE OF A
content
rendering pixels
content
NOT "content"
content::WebContents
Blink
cc
content
(other kinds of rendered content: <video>, <canvas>, WebAssembly, WebGL, WebVR, PDF, ...)
content
https://www.nytimes.com
pixels
( )
( )
Operating System
( ?)
Device Driver
#include <GL/gl.h>
● textures
● shaders
● vertex buffers
● …
goals
● JavaScript
up
up
up
d
d
● user input
ate
ate
ate
● asynchronous loading
initial render
● animations
● scrolling
● zooming
time
stages
lifecycle
pixels
content
<html>...</html> stage ? stage ? stage
bu
DIV
il
ds
P
● HTML tags can nest Text
P
● an object model reflects the
containment relationships Text
DOM
P ● parents
● children
Text
● siblings
DOM
The DOM is both
Document
● Chrome's internal representation
HTML
AND
BODY ● the API exposed to JavaScript
DIV
var div = document.body.firstChild;
P
var p2 = div.childNodes[1];
Text p2.appendChild(document.createElement("span"));
p2.foo = {arbitrary: "state"};
P
[ JS ]
Text
[bindings] V8
DOM
<my-widget> customElements.define('my-widget',
<b>inside</b> class extends HTMLElement { constructor() { super();
</my-widget> this.attachShadow({mode: 'open'}).innerHTML =
"<wrapper><slot /></wrapper>"; }});
<my-widget> ShadowRoot
ShadowRoot()
<wrapper>
<b> <slot>
A custom element
AssignedNodes()
host tree has a shadow tree.
shadow tree
DOM
FlatTreeTraversal
<my-widget> ShadowRoot
ShadowRoot()
<wrapper> <my-widget>
DIV
ts
P
ec
sel hello
Text world
Text
style
font-weight: bold; hello
CSSPropertyValueSet
BorderLeftColor
CSSSelectorList
CSSPropertyValue CSSColorValue
CSSSelector Property()
Value() 0x0000FFFF
style
StyleSheetContents
StyleSheetContents
StyleSheetContents
Document::UpdateStyle
HTML ComputedStyle
BODY ComputedStyle
ComputedStyle {
fontWeight = ...
marginLeft = ...
DIV ComputedStyle
outline = ...
transform = ...
P ComputedStyle background = ...
...
Text ComputedStyle
}
P ComputedStyle
Style recalc: for every node in the DOM tree,
Text ComputedStyle
compute the value of every style property.
style
getComputedStyle(element)["padding-top"] [ JS ]
DIV
LayoutRect
x = 183
y = 148
width = 402
height = 116
layout
block flow
Simple "block" layout objects
are placed one after another,
flowing down the page.
layout
<span class="bigger">
#text
Lorem ipsum dolor sit amet, line break
اﻟﻌﺮﺑﯿﺔ
consectetur adipiscing elit. ִעב ְִרית
(Some languages flow right-to-left.)
layout
Layout measures runs of text in fonts.
"fire"
Font
HarfBuzzShaper ShapeResult
HarfBuzz
fire
Shaping selects the glyphs and
computes their placement.
layout
AWESOME
● <table>
● float: left
● column-count: 3
● display: flex
● writing-mode: vertical-lr
● ...
layout
DOM tree layout tree StyleEngine::RebuildLayoutTree
BODY LayoutBlockFlow
Each layout pass
DIV LayoutBlockFlow
walks the layout tree,
P LayoutBlockFlow computing the visual
Text LayoutText geometry of each
LayoutObject.
P LayoutBlockFlow
layout
DOM nodes are not 1:1 with layout objects. <div>
ComputedStyle {
display: none
<div> block </div> LayoutBlock DIV }
<span> inline </span>
LayoutBlock (anonymous)
no LayoutObject!
LayoutInline SPAN
no DOM node!
<my-widget>
LayoutNGMixin
LayoutNGMixin 🔍
LayoutNGMixin
LayoutObject 🔍
layout
LayoutNG separates the
LayoutObject inputs and outputs of layout. NGConstraintSpace
LayoutNGMixin NGLayoutInputNode
✓
✗
UpdateLayout()
LayoutNGMixin NGLayoutInputNode
NGLayoutAlgorithm
LayoutObject
NGLayoutResult
LayoutObject immutable!
layout
LayoutObject
LayoutNGMixin NGPhysicalFragment
UpdateLayout() NGLayoutResult NGPhysicalFragment
NGPhysicalFragment
LayoutNGMixin
LayoutObject
DIV LayoutObject
Paint() PaintCanvas::drawRect
PaintArtifact
DisplayItem paint op buffer
PO DrawRectOp PO PO … display
- rect {x, y, w, h} item
- PaintFlags {color, …} list
paint
Paint uses stacking order, BODY
DIV .green
DOM tree
<div class="yellow"></div>
<div class="green"></div>
<style>
.yellow { z-index: 2; ... }
.green { z-index: 1; ... }
</style> yellow paints last
paint
Each paint phase is a separate
<div id="green">
traversal of a stacking context.
green's text
</div>
paint phases <div id="blue"></div>
(simplified) backgrounds
floats
foregrounds
outlines
blue after green, but
foregrounds after backgrounds
paint — example
<style> #p {
position: absolute; padding: 2px;
width: 50px; height: 20px;
left: 25px; top: 25px;
border: 4px solid purple;
background-color: lightgrey;
} </style>
<div id=p> pixels </div>
paint — example
<style> #p {
position: absolute; padding: 2px;
width: 50px; height: 20px;
left: 25px; top: 25px;
border: 4px solid purple;
background-color: lightgrey;
} </style>
<div id=p> pixels </div>
paint — example
<style> #p {
DrawingDocumentBackground
position: absolute; padding: 2px;
DrawRectOp width: 50px; height: 20px;
{0, 0, 610, 316} kFill_Style left: 25px; top: 25px;
border: 4px solid purple;
DrawingBoxDecorationBackground background-color: lightgrey;
DrawRectOp } </style>
{25, 25, 87, 57} kFill_Style <div id=p> pixels </div>
DrawRectOp
{27, 27, 85, 55} kStroke_Style (w=4)
DrawingPaintPhaseForeground
DrawTextBlobOp
{31, 45} "pixels" display items
paint — example
DrawingPaintPhaseForeground <style> #p {
position: absolute; padding: 2px;
DrawTextBlobOp width: 50px; height: 20px;
{31, 45} left: 25px; top: 25px;
border: 4px solid purple;
SkTextBlob background-color: lightgrey;
} </style>
53 4C 5B 48 4F 56 <div id=p> pixels </div>
0.0 8.0 12.4 20.4 27.5 32.0
raster
cc::ResourcePool::InUsePoolResource
cc::DisplayItemList
PaintOp …
raster
paint
PaintImage
ImageDecodeCache
raster
InUsePoolResource
cc::DisplayItemList
PaintOp … GpuRasterBacking
GL texture ID
Raster can be accelerated by the GPU.
GPU memory
raster
Raster uses the Skia
DrawRectOp graphics library to
Raster() DrawRectOp::RasterWithFlags
{rect, flags}
issue GL calls.
SkCanvas::drawRect
GrRenderTargetContext::addDrawOp
RasterTaskImpl
GPU process
RasterInterface PaintOp::Raster
renderer process
GPU process
GpuChannelHost
GpuChannel
RasterInterface
RasterDecoderImpl
GPU RasterCHROMIUM
command
buffer PaintOp PaintOp …
gpu
GPU process In the GPU process, the GL functions
link dynamically to native OpenGL.
GLApi::glDrawArraysFn
On Windows, we translate to DirectX.
dlopen("libGLESv2.so") ANGLE
dlsym("glDrawArrays")
LoadLibrary("libglesv2.dll")
GetProcAddress("glDrawArrays")
change
DOM
We now have a complete pipeline.
(in memory)
frames
The renderer produces animation frames.
time
VSync signal
= time spent to render the frame
invalidation
Each pipeline stage tracks granular asynchronous invalidations.
Node::SetNeedsStyleRecalc() style
LayoutObject::SetNeedsLayout() layout
PaintInvalidator::InvalidatePaint() paint
RasterInvalidator::Generate() raster
scroll
main
time
<script>
mineSomeBitcoins(); // why not?
</script>
enter: compositing
● Decompose the page into layers
lay
ers
which raster independently.
in
De
● Combine the layers on another thread.
ve
lop
er
To
o
main build layers
ls
commit
impl* draw layers
BODY
DIV #text
P #text
BODY
DIV #text
P #text
Animation:
a layer moves
Scrolling:
a layer moves;
another clips
threaded input
renderer process
main busy
LayoutText PaintLayer is a
compositing layer tree list
LayoutBlockFlow "candidate".
layout tree
Layers are created by "promoting"
elements with compositing triggers.
scrolling layers
LayoutBlockFlow PaintLayer main layer
solid background?
no non-composited
scroller
compositing
DOM style layout paint
assignments
main
GraphicsLayer::Paint
PaintLayerCompositor::UpdateAssignmentsIfNeeded
cc::Layer
GraphicsLayer cc::Layer DI DI DI
bu
ild
GraphicsLayer cc::Layer
s
PrePaintTreeWalk::Walk
PaintPropertyTreeBuilder
PaintArtifact
PaintArtifactCompositor cc::Layer
PaintOp …
compositing
... prepaint paint composite
assignments
main
main … paint
(blocked) cc::Layer
impl commit …
LayerImpl
tiling
impl prepare tiles rastered
tile
viewport
visible
tiles
raster raster task
raster
CategorizedWorkerPool
CompositorFrame
PictureLayerImpl::AppendQuads DrawQuad
DrawQuaDra
DrawQuad
wQuad GPU
d rect = … process
Tile GPU memory
TileDrawInfo
resource_
commit
Drawing can continue while
a new commit is rastered.
pending
tree impl
LayerImpl raster activation
active
tree
LayerImpl LayerImpl
draw draw
display (viz)
The display compositor
combines frames for multiple surfaces.
browser process
browser UI
ui::Compositor GPU process
CompositorFrame viz
display
renderer process CompositorFrame compositor
SurfaceAggregator
renderer process CompositorFrame
display (viz)
GPU process
Display::DrawAndSwap CompositorFrame
DrawQuad
DrawQuad
GLRenderer::DrawTileQuad
viz GLES2Implementation
command
buffer
gpu
Viz draws quads
GLES2DecoderImpl to the back buffer.
display (viz)
GPU process
Display::DrawAndSwap CompositorFrame
DrawQuad
DrawQuad
SkiaRenderer::DrawTileDrawQuad
viz
SkDeferredDisplayList
gpu SkSurface::draw
SkiaOutputSurfaceImplOnGpu
display (viz)
viz GLRenderer::SwapBuffers
eglSwapBuffers(...)
review content
<html>...</html>
GPU process
raster display
end LIFE OF A
slides: bit.ly/lifeofapixel
feedback: [email protected]