mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Merge pull request #982 from Hixie/fewer-bit-updates
Less tree walking for compositing bits updates.
This commit is contained in:
commit
e48efdca15
@ -69,7 +69,7 @@ abstract class Renderer extends Scheduler
|
||||
void beginFrame() {
|
||||
assert(renderView != null);
|
||||
RenderObject.flushLayout();
|
||||
renderView.updateCompositingBits();
|
||||
RenderObject.flushCompositingBits();
|
||||
RenderObject.flushPaint();
|
||||
renderView.compositeFrame();
|
||||
}
|
||||
|
||||
@ -391,6 +391,10 @@ RenderingExceptionHandler debugRenderingExceptionHandler;
|
||||
/// for their children.
|
||||
abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
|
||||
RenderObject() {
|
||||
_needsCompositing = hasLayer;
|
||||
}
|
||||
|
||||
// LAYOUT
|
||||
|
||||
/// Data for use by the parent render object.
|
||||
@ -492,7 +496,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
}
|
||||
}
|
||||
|
||||
static List<RenderObject> _nodesNeedingLayout = new List<RenderObject>();
|
||||
static List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
|
||||
bool _needsLayout = true;
|
||||
/// Whether this render object's layout information is dirty.
|
||||
bool get needsLayout => _needsLayout;
|
||||
@ -597,11 +601,11 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
// TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themeselves
|
||||
while (_nodesNeedingLayout.isNotEmpty) {
|
||||
List<RenderObject> dirtyNodes = _nodesNeedingLayout;
|
||||
_nodesNeedingLayout = new List<RenderObject>();
|
||||
dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)..forEach((RenderObject node) {
|
||||
_nodesNeedingLayout = <RenderObject>[];
|
||||
for (RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
|
||||
if (node._needsLayout && node.attached)
|
||||
node._layoutWithoutResize();
|
||||
});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
_debugDoingLayout = false;
|
||||
@ -822,7 +826,8 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
static RenderObject _debugActivePaint = null;
|
||||
static RenderObject get debugActivePaint => _debugActivePaint;
|
||||
|
||||
static List<RenderObject> _nodesNeedingPaint = new List<RenderObject>();
|
||||
static List<RenderObject> _nodesNeedingPaint = <RenderObject>[];
|
||||
static List<RenderObject> _nodesNeedingCompositingBitsUpdate = <RenderObject>[];
|
||||
|
||||
/// Whether this render object paints using a composited layer.
|
||||
///
|
||||
@ -843,49 +848,79 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
return _layer;
|
||||
}
|
||||
|
||||
bool _needsCompositingBitsUpdate = true;
|
||||
bool _needsCompositingBitsUpdate = false; // set to true when a child is added
|
||||
/// Mark the compositing state for this render object as dirty.
|
||||
///
|
||||
/// When the subtree is mutated, we need to recompute our [needsCompositing]
|
||||
/// bit, and our ancestors need to do the same (in case ours changed).
|
||||
/// Therefore, [adoptChild] and [dropChild] call
|
||||
/// [markNeedsCompositingBitsUpdate].
|
||||
/// When the subtree is mutated, we need to recompute our
|
||||
/// [needsCompositing] bit, and some of our ancestors need to do the
|
||||
/// same (in case ours changed in a way that will change theirs). To
|
||||
/// this end, [adoptChild] and [dropChild] call this method, and, as
|
||||
/// necessary, this method calls the parent's, etc, walking up the
|
||||
/// tree to mark all the nodes that need updating.
|
||||
///
|
||||
/// This method does not schedule a rendering frame, because since
|
||||
/// it cannot be the case that _only_ the compositing bits changed,
|
||||
/// something else will have scheduled a frame for us.
|
||||
void _markNeedsCompositingBitsUpdate() {
|
||||
if (_needsCompositingBitsUpdate)
|
||||
return;
|
||||
_needsCompositingBitsUpdate = true;
|
||||
final AbstractNode parent = this.parent;
|
||||
if (parent is RenderObject)
|
||||
parent._markNeedsCompositingBitsUpdate();
|
||||
assert(parent == this.parent);
|
||||
}
|
||||
|
||||
bool _needsCompositing = false;
|
||||
/// Whether we or one of our descendants has a compositing layer.
|
||||
///
|
||||
/// Only legal to call after [flushLayout] and [updateCompositingBits] have
|
||||
/// been called.
|
||||
bool get needsCompositing {
|
||||
assert(!_needsCompositingBitsUpdate); // make sure we don't use this bit when it is dirty
|
||||
return _needsCompositing;
|
||||
if (parent is RenderObject) {
|
||||
final RenderObject parent = this.parent;
|
||||
if (parent._needsCompositingBitsUpdate)
|
||||
return;
|
||||
if (!hasLayer && !parent.hasLayer) {
|
||||
parent._markNeedsCompositingBitsUpdate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(() {
|
||||
final AbstractNode parent = this.parent;
|
||||
if (parent is RenderObject)
|
||||
return parent._needsCompositing;
|
||||
return true;
|
||||
});
|
||||
// parent is fine (or there isn't one), but we are dirty
|
||||
_nodesNeedingCompositingBitsUpdate.add(this);
|
||||
}
|
||||
|
||||
/// Updates the [needsCompositing] bits.
|
||||
///
|
||||
/// Called as part of the rendering pipeline after [flushLayout] and before
|
||||
/// [flushPaint].
|
||||
void updateCompositingBits() {
|
||||
static void flushCompositingBits() {
|
||||
Timeline.startSync('Compositing Bits');
|
||||
_nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
|
||||
for (RenderObject node in _nodesNeedingCompositingBitsUpdate) {
|
||||
if (node.attached)
|
||||
node._updateCompositingBits();
|
||||
}
|
||||
_nodesNeedingCompositingBitsUpdate.clear();
|
||||
Timeline.finishSync();
|
||||
}
|
||||
|
||||
bool _needsCompositing; // initialised in the constructor
|
||||
/// Whether we or one of our descendants has a compositing layer.
|
||||
///
|
||||
/// Only legal to call after [flushLayout] and [flushCompositingBits] have
|
||||
/// been called.
|
||||
bool get needsCompositing {
|
||||
assert(!_needsCompositingBitsUpdate); // make sure we don't use this bit when it is dirty
|
||||
return _needsCompositing;
|
||||
}
|
||||
|
||||
void _updateCompositingBits() {
|
||||
if (!_needsCompositingBitsUpdate)
|
||||
return;
|
||||
bool didHaveCompositedDescendant = _needsCompositing;
|
||||
bool oldNeedsCompositing = _needsCompositing;
|
||||
visitChildren((RenderObject child) {
|
||||
child.updateCompositingBits();
|
||||
child._updateCompositingBits();
|
||||
if (child.needsCompositing)
|
||||
_needsCompositing = true;
|
||||
});
|
||||
if (hasLayer)
|
||||
_needsCompositing = true;
|
||||
if (didHaveCompositedDescendant != _needsCompositing)
|
||||
if (oldNeedsCompositing != _needsCompositing)
|
||||
markNeedsPaint();
|
||||
_needsCompositingBitsUpdate = false;
|
||||
}
|
||||
@ -946,7 +981,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
|
||||
_debugDoingPaint = true;
|
||||
try {
|
||||
List<RenderObject> dirtyNodes = _nodesNeedingPaint;
|
||||
_nodesNeedingPaint = new List<RenderObject>();
|
||||
_nodesNeedingPaint = <RenderObject>[];
|
||||
// Sort the dirty nodes in reverse order (deepest first).
|
||||
for (RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
|
||||
assert(node._needsPaint);
|
||||
|
||||
@ -21,6 +21,7 @@ class TestRenderView extends RenderView {
|
||||
|
||||
enum EnginePhase {
|
||||
layout,
|
||||
compositingBits,
|
||||
paint,
|
||||
composite
|
||||
}
|
||||
@ -39,7 +40,9 @@ class TestRenderingFlutterBinding extends BindingBase with Scheduler, Renderer,
|
||||
RenderObject.flushLayout();
|
||||
if (phase == EnginePhase.layout)
|
||||
return;
|
||||
renderer.renderView.updateCompositingBits();
|
||||
RenderObject.flushCompositingBits();
|
||||
if (phase == EnginePhase.compositingBits)
|
||||
return;
|
||||
RenderObject.flushPaint();
|
||||
if (phase == EnginePhase.paint)
|
||||
return;
|
||||
|
||||
@ -10,18 +10,21 @@ import 'rendering_tester.dart';
|
||||
void main() {
|
||||
test('Stack can layout with top, right, bottom, left 0.0', () {
|
||||
RenderBox size = new RenderConstrainedBox(
|
||||
additionalConstraints: new BoxConstraints.tight(const Size(100.0, 100.0)));
|
||||
additionalConstraints: new BoxConstraints.tight(const Size(100.0, 100.0))
|
||||
);
|
||||
|
||||
RenderBox red = new RenderDecoratedBox(
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: const Color(0xFFFF0000)
|
||||
),
|
||||
child: size);
|
||||
child: size
|
||||
);
|
||||
|
||||
RenderBox green = new RenderDecoratedBox(
|
||||
decoration: new BoxDecoration(
|
||||
backgroundColor: const Color(0xFFFF0000)
|
||||
));
|
||||
)
|
||||
);
|
||||
|
||||
RenderBox stack = new RenderStack(children: <RenderBox>[red, green]);
|
||||
(green.parentData as StackParentData)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user