Gecko:DisplayListBasedInvalidation: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
No edit summary
Line 5: Line 5:
= Basic Outline =
= Basic Outline =


* Display List changes
There are 3 main components to DLBI: Frame invalidation, display list invalidation and layer tree invalidation.
** We want to compare the new display to the old one and invalidate layer regions of anything that has changed.
** We already cache most of the information that we need, and iterate over it in FrameLayerBuilder.
*** We need to add the old bounds of the display item into the cached data
*** Some items (e.g. borders) need two rectangles: an outer rect and an inner rect
** Invalidating display items that no longer exist.
*** How do we do this?
*** We could iterate over the frames DisplayItemData at the end of nsFrame::BuildDisplayList, and send invalidations for any display item types that weren't just created.
*** FrameLayerBuilder already detects items being added to or removed from a layer, so this won't be a problem if we do the processing in FrameLayerBuilder


* Style and other changes
== Frame Invalidation ==
** These should invalidate all (?) display items for the frame, so we can just set a dirty bit on the frame and check this from FrameLayerBuilder
 
Code lives in layout/generic/nsIFrame.h and layout/generic/nsFrame.cpp
 
This is used when a frame has a major change that will affect rendering (such as a style change) and all display items belonging to this frame should redraw their content.
 
nsIFrame::InvalidateFrame() marks the frame as invalid. You can also specify a rect using nsIFrame::InvalidateFrameWithRect, but note that this is a minimum, the display items created by this frame can still choose to invalidate further.
 
== Display List Invalidation ==
 
Compute the area of a ThebesLayer by comparing the current display list being drawn into the layer against the previous display list.
 
Code lives in layout/base/FrameLayerBuilder.cpp, primarily in FrameLayerBuilder::InvalidateForLayerChange(). The nsDisplayItemGeometry classes in layout/base/nsDisplayListInvalidation.h, and layout/base/nsDisplayList.h - nsDisplayItem::AllocateGeometry(), nsDisplayItem::ComputeInvalidationRegion.
 
Every display item is asked to allocate a geometry object that is retained between paints and then used to check for display item changes.
 
When painting, it checks if it has been added or removed from the layer and invalidates the bounds of the display item if so.
 
Items that exist between paints are asked to check for size changes using nsDisplayItem::ComputeInvalidationRegion and will compute the changed area (if any).
 
== Layer Tree Invalidation ==
 
Code lives in gfx/layers/LayerTreeInvalidation.{h,cpp}.
 
Computes changes in layer trees and reports the invalid area.
 
Used to find changes in inactive layer trees, compute widget dirty rects (BasicLayers only) and report MozAfterPaint events.


= Potential Problems =
= Potential Problems =

Revision as of 04:47, 4 October 2012

Display List Based Invalidation - Bug 539356

Instead of invalidating areas of the screen as we do currently, we want invalidation to happen at the display list/layer boundary to reduce unnecessary redrawing

Basic Outline

There are 3 main components to DLBI: Frame invalidation, display list invalidation and layer tree invalidation.

Frame Invalidation

Code lives in layout/generic/nsIFrame.h and layout/generic/nsFrame.cpp

This is used when a frame has a major change that will affect rendering (such as a style change) and all display items belonging to this frame should redraw their content.

nsIFrame::InvalidateFrame() marks the frame as invalid. You can also specify a rect using nsIFrame::InvalidateFrameWithRect, but note that this is a minimum, the display items created by this frame can still choose to invalidate further.

Display List Invalidation

Compute the area of a ThebesLayer by comparing the current display list being drawn into the layer against the previous display list.

Code lives in layout/base/FrameLayerBuilder.cpp, primarily in FrameLayerBuilder::InvalidateForLayerChange(). The nsDisplayItemGeometry classes in layout/base/nsDisplayListInvalidation.h, and layout/base/nsDisplayList.h - nsDisplayItem::AllocateGeometry(), nsDisplayItem::ComputeInvalidationRegion.

Every display item is asked to allocate a geometry object that is retained between paints and then used to check for display item changes.

When painting, it checks if it has been added or removed from the layer and invalidates the bounds of the display item if so.

Items that exist between paints are asked to check for size changes using nsDisplayItem::ComputeInvalidationRegion and will compute the changed area (if any).

Layer Tree Invalidation

Code lives in gfx/layers/LayerTreeInvalidation.{h,cpp}.

Computes changes in layer trees and reports the invalid area.

Used to find changes in inactive layer trees, compute widget dirty rects (BasicLayers only) and report MozAfterPaint events.

Potential Problems

  • Window resizing / incremental loading
    • We want to make sure that we are only invalidating the new areas, not the entire page
  • Bordered frame size changes
    • We don't really want to invalidate the entire area here, but we do need to invalidate some of the internal area as well as the extended bounds.


Debugging Invalidations Problems

Invalidation Logging

Enable this by defining 'DEBUG_INVALIDATIONS' in nsViewManager.cpp and FrameLayerBuilder.cpp and recompile/link these files. Running with MOZ_DUMP_PAINT_LIST=1 in your environment is recommended to view the display list that is being analyzed by DLBI, but note that this adds a huge amount of extra log data.

This should then dump (to stdout) all invalidations generated by DLBI, along with the reason. Note that this doesn't include invalidations that come from the layers system (e.g. new layer creation, or layer backing store deleted due to inactivity).

There are five general reasons for invalidation:

  • Content added - Display item type SolidColor(0x116116c08) added to layer 0x119286800!
    • New display item added that didn't exist during the previous paint, we invalidate the value of nsDisplayItemGeometry::ComputeInvalidationRegion()
  • Content removed - Invalidating unused display item (67) belonging to frame 0x11b5bb288 from layer 0x116fd4800
    • Display item from the previous paint doesn't exist during this paint, we invalidate the value of nsDisplayItemGeometry::ComputeInvalidationRegion()
    • The (67) value is the display item key, see layout/base/nsDisplayItemTypes.h
  • Invalid frame - Display item type nsDisplaySVGPathGeometry(0x11c7ffae8) (in layer 0x11c51b000) belongs to an invalidated frame!
    • The frame that created the item has been marked (via nsIFrame::InvalidateFrame) as needing all its content redrawn.
    • We invalidate the value of nsDisplayItemGeometry::ComputeInvalidationRegion()
  • Content changed size - Display item type TableBorderBackground(0x11a885748) (in layer 0x11b884c00) changed geometry!
    • The display item itself has determined that its size has changed, and determined what area needs to be repainted.
    • The virtual implementation of nsDisplayItem::ComputeInvalidationRegion() does this calculaton.
  • Inactive Layer tree has changed - Inactive LayerManager(0x11a3e8e20) for display item Opacity(0x116bf6560) has an invalid region - invalidating layer 0x119286800
    • When we have an inactive layer subtree, DLBI runs on the individual layers (and is logged as such) and we run LayerTreeInvalidation to find the changed area of the layer tree.



Logging Wish List:

  • Print paint count to the log as well as put it onscreen to help correlating observed bugs with log data.
  • Easier way to enable/disable logging, have it work in opt builds.
  • Make logging work on Android.
  • Convert display item type numbers to names.
  • View the inactive layer trees created/processed when MOZ_DUMP_PAINT_LIST=1

Other Useful Tools

  • Turn on paint flashing pref - nglayout.debug.paint_flashing