Skip to content

Instantly share code, notes, and snippets.

@basecode
Last active December 26, 2015 10:09
Show Gist options
  • Save basecode/7134962 to your computer and use it in GitHub Desktop.
Save basecode/7134962 to your computer and use it in GitHub Desktop.
DOM Renderer

A quick draft of a "layered based" DOM renderer.

Why Layers?

A Layer, also referred to as "Stacking Context", describes a group of DisplayObjects that can be flattened and combined to one "Context". Why does that matter? Chances are supposed to be higher that continuous attribute changes due to animations can be applied much faster on a Layer that can potentially managed by GPU than on all children individually managed by GPU or even CPU. Especially when considering a frame-budget of only 16ms. Which means the animation could run at 60FPS.

When to create a Layer?

A Layer can be created for the following reasons:

  • Depends on attributes. Those attributes can be applied directly by GPU and CPU goes idle. That's why it makes sense to create implicitly a Layer when such attributes are animated.

    • 3d transform
    • opacity < 1
 <div data-name="ImplicitLayer" style="matrix3d(…); opacity:0.9;">
   /* svg, png, canvas, dom, whatever */
 </div>

Source 1: http://www.html5rocks.com/en/tutorials/speed/high-performance-animations/

Source 2: http://www.w3.org/TR/2013/WD-compositing-1-20131010/#csscompositingrules_SVG

Source 3: http://nimbu.in/html5devconf-oct/#/step-30

  • Depends on Container API usage. A Layer could be explicitly created by the User. Bonsai could offer a "FlatGroup" API so a User knows that everything that was added to a FlatGroup is going to be flattened on Renderer side. Animating the attributes of the children of the group is forbidden (and probably causes a warning within Pixelplant Creator). From now on only animations applied on the FlatGroup are allowed.

    • FlatGroup API
 <div data-name="FlatGroupLayer">
  /* svg, png, canvas, dom, whatever */
 </div>

https://github.com/uxebu/bonsai/blob/master/src/runner/group.js

  • Depends on Drawing API usage Playing a video or audio, morphing, animating "filter" or "mask" can potentially be faster using a certain Drawing API, which is probably managed by GPU. In such cases it would make sense to create a Layer whereby the Drawing Context reflects the Stacking Context.

    • Path (SVG or Canvas2d, WebGL)
    • Text (DOM)
    • Video
    • Audio
 <video data-name="VideoLayer" style="matrix3d(…); opacity:0.9;" />
 <svg data-name="SvgLayer" style="matrix3d(…); opacity:0.9;" />

http://on-demand.gputechconf.com/gtc/2012/presentations/S0024-GPU-Accelerated-Path-Rendering.pdf

Possible Architecture

The Renderer receives drawing instructions. Those instructions look like this:

Non-Animatable Instructions

{
  id: 1,
  type: 'Bitmap',
  attributes: { matrix: […] },
  animated: false
}

The class RenderObjectFactory would parse the instructions. At first it tries to determine the best available RendererObject for a specific "type".

myRendererObjectFactory.createFrom(message); // DomRenderObject

This results in the following HTML fragment. Since message.animated is false the RenderObject does not create a GPULayer and uses matrix (2d) for geometry.

  <div data-id="0" style="width:500px; height:500px;">
     <img src="" data-id="1" style="matrix(1, 0, 0, 1, 50, 50)" /> <!-- CPULayer //-->
  </div>

Animated Instructions

{
  id: 1,
  type: 'Bitmap',
  attributes: { matrix: […] },
  animated: true
}

This time DomRenderObject would apply matrix3d and therefore trigger a GPULayer.

  <div data-id="0" style="width:500px; height:500px;">
     <img src="" data-id="1" style="matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 50, 50, 0, 1)" /> <!-- GPULayer //-->
  </div>

Now let's consider the following drawing instructions where matrix and filter are supposed to be animated:

{
  id: 1,
  type: 'Bitmap',
  attributes: { matrix: […], filter: […] },
  animated: true
}

Let's say DomRenderObject can't apply filter and that's why SvgRenderObject would take over rendering. Although the RenderObject is supposed to be animated and SvgRenderObject can try to create a GPULayer by applying matrix3d, I assume it can't make use of GPU, since the use of filter effects.

  <div data-id="0" style="width:500px; height:500px;">
     <svg data-id="1" style="matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 50, 50, 0, 1)">
       <def><filter id="myFilter">…</filter></defs>
       <image filter="#myFilter" />
     </svg>
  </

The terms GPULayer and CPULayer are used to express what drawing-path should be used. Obviously in reality we can't control the drawing-path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment