Switch from ui.tracing to dart:Developer Timeline

This change will let us remove the tracing interface from dart:ui and also
makes these timeline events show up in Observatory.
This commit is contained in:
Adam Barth 2015-11-18 12:55:07 -08:00
parent e1b721f068
commit c964a1f1f8
5 changed files with 63 additions and 47 deletions

View file

@ -2,43 +2,44 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:developer';
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'dart:ui' as ui;
Duration timeBase = null;
void beginFrame(Duration timeStamp) {
ui.tracing.begin('beginFrame');
if (timeBase == null)
timeBase = timeStamp;
double delta = (timeStamp - timeBase).inMicroseconds / Duration.MICROSECONDS_PER_MILLISECOND;
Timeline.timeSync('beginFrame', () {
if (timeBase == null)
timeBase = timeStamp;
double delta = (timeStamp - timeBase).inMicroseconds / Duration.MICROSECONDS_PER_MILLISECOND;
// paint
ui.Rect paintBounds = ui.Point.origin & ui.window.size;
ui.PictureRecorder recorder = new ui.PictureRecorder();
ui.Canvas canvas = new ui.Canvas(recorder, paintBounds);
canvas.translate(paintBounds.width / 2.0, paintBounds.height / 2.0);
canvas.rotate(math.PI * delta / 1800);
canvas.drawRect(new ui.Rect.fromLTRB(-100.0, -100.0, 100.0, 100.0),
new ui.Paint()..color = const ui.Color.fromARGB(255, 0, 255, 0));
ui.Picture picture = recorder.endRecording();
// paint
ui.Rect paintBounds = ui.Point.origin & ui.window.size;
ui.PictureRecorder recorder = new ui.PictureRecorder();
ui.Canvas canvas = new ui.Canvas(recorder, paintBounds);
canvas.translate(paintBounds.width / 2.0, paintBounds.height / 2.0);
canvas.rotate(math.PI * delta / 1800);
canvas.drawRect(new ui.Rect.fromLTRB(-100.0, -100.0, 100.0, 100.0),
new ui.Paint()..color = const ui.Color.fromARGB(255, 0, 255, 0));
ui.Picture picture = recorder.endRecording();
// composite
final double devicePixelRatio = ui.window.devicePixelRatio;
ui.Rect sceneBounds = new ui.Rect.fromLTWH(0.0, 0.0, ui.window.size.width * devicePixelRatio, ui.window.size.height * devicePixelRatio);
Float64List deviceTransform = new Float64List(16)
..[0] = devicePixelRatio
..[5] = devicePixelRatio
..[10] = 1.0
..[15] = 1.0;
ui.SceneBuilder sceneBuilder = new ui.SceneBuilder(sceneBounds)
..pushTransform(deviceTransform)
..addPicture(ui.Offset.zero, picture, paintBounds)
..pop();
ui.window.render(sceneBuilder.build());
// composite
final double devicePixelRatio = ui.window.devicePixelRatio;
ui.Rect sceneBounds = new ui.Rect.fromLTWH(0.0, 0.0, ui.window.size.width * devicePixelRatio, ui.window.size.height * devicePixelRatio);
Float64List deviceTransform = new Float64List(16)
..[0] = devicePixelRatio
..[5] = devicePixelRatio
..[10] = 1.0
..[15] = 1.0;
ui.SceneBuilder sceneBuilder = new ui.SceneBuilder(sceneBounds)
..pushTransform(deviceTransform)
..addPicture(ui.Offset.zero, picture, paintBounds)
..pop();
ui.window.render(sceneBuilder.build());
});
ui.tracing.end('beginFrame');
ui.window.scheduleFrame();
}

View file

@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'dart:collection';
import 'dart:developer';
import 'dart:ui' as ui;
/// Slows down animations by this factor to help in development.
@ -42,19 +43,9 @@ class Scheduler {
int get transientCallbackCount => _transientCallbacks.length;
/// Called by the engine to produce a new frame.
///
/// This function first calls all the callbacks registered by
/// [requestAnimationFrame], then calls all the callbacks registered by
/// [addPersistentFrameCallback], which typically drive the rendering pipeline,
/// and finally calls the callbacks registered by [requestPostFrameCallback].
void beginFrame(Duration rawTimeStamp) {
assert(!_inFrame);
_inFrame = true;
Duration timeStamp = new Duration(
microseconds: (rawTimeStamp.inMicroseconds / timeDilation).round());
_haveScheduledVisualUpdate = false;
void _invokeAnimationCallbacks(Duration timeStamp) {
Timeline.startSync('Animate');
assert(_inFrame);
Map<int, SchedulerCallback> callbacks = _transientCallbacks;
_transientCallbacks = new Map<int, SchedulerCallback>();
callbacks.forEach((int id, SchedulerCallback callback) {
@ -62,6 +53,23 @@ class Scheduler {
invokeCallback(callback, timeStamp);
});
_removedIds.clear();
Timeline.finishSync();
}
/// Called by the engine to produce a new frame.
///
/// This function first calls all the callbacks registered by
/// [requestAnimationFrame], then calls all the callbacks registered by
/// [addPersistentFrameCallback], which typically drive the rendering pipeline,
/// and finally calls the callbacks registered by [requestPostFrameCallback].
void beginFrame(Duration rawTimeStamp) {
Timeline.startSync('Begin frame');
assert(!_inFrame);
_inFrame = true;
Duration timeStamp = new Duration(
microseconds: (rawTimeStamp.inMicroseconds / timeDilation).round());
_haveScheduledVisualUpdate = false;
_invokeAnimationCallbacks(timeStamp);
for (SchedulerCallback callback in _persistentCallbacks)
invokeCallback(callback, timeStamp);
@ -73,6 +81,7 @@ class Scheduler {
invokeCallback(callback, timeStamp);
_inFrame = false;
Timeline.finishSync();
}
void invokeCallback(SchedulerCallback callback, Duration timeStamp) {

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:developer';
import 'dart:math' as math;
import 'dart:ui' as ui;
@ -610,7 +611,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
///
/// See [FlutterBinding] for an example of how this function is used.
static void flushLayout() {
ui.tracing.begin('RenderObject.flushLayout');
Timeline.startSync('Layout');
_debugDoingLayout = true;
try {
// TODO(ianh): assert that we're not allowing previously dirty nodes to redirty themeselves
@ -624,7 +625,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
}
} finally {
_debugDoingLayout = false;
ui.tracing.end('RenderObject.flushLayout');
Timeline.finishSync();
}
}
void _layoutWithoutResize() {
@ -962,7 +963,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
///
/// See [FlutterBinding] for an example of how this function is used.
static void flushPaint() {
ui.tracing.begin('RenderObject.flushPaint');
Timeline.startSync('Paint');
_debugDoingPaint = true;
try {
List<RenderObject> dirtyNodes = _nodesNeedingPaint;
@ -976,7 +977,7 @@ abstract class RenderObject extends AbstractNode implements HitTestTarget {
assert(_nodesNeedingPaint.length == 0);
} finally {
_debugDoingPaint = false;
ui.tracing.end('RenderObject.flushPaint');
Timeline.finishSync();
}
}

View file

@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:developer';
import 'dart:ui' as ui;
import 'package:flutter/animation.dart';
@ -116,7 +117,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
///
/// Actually causes the output of the rendering pipeline to appear on screen.
void compositeFrame() {
ui.tracing.begin('RenderView.compositeFrame');
Timeline.startSync('Composite');
try {
(layer as TransformLayer).transform = _logicalToDeviceTransform;
Rect bounds = Point.origin & (size * ui.window.devicePixelRatio);
@ -126,7 +127,7 @@ class RenderView extends RenderObject with RenderObjectWithChildMixin<RenderBox>
ui.window.render(scene);
scene.dispose();
} finally {
ui.tracing.end('RenderView.compositeFrame');
Timeline.finishSync();
}
}

View file

@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:developer';
import 'package:flutter/animation.dart';
import 'package:flutter/rendering.dart';
@ -47,6 +49,7 @@ class WidgetFlutterBinding extends FlutterBinding {
void buildDirtyElements() {
if (_dirtyElements.isEmpty)
return;
Timeline.startSync('Build');
BuildableElement.lockState(() {
_dirtyElements.sort((BuildableElement a, BuildableElement b) => a.depth - b.depth);
int dirtyCount = _dirtyElements.length;
@ -63,6 +66,7 @@ class WidgetFlutterBinding extends FlutterBinding {
_dirtyElements.clear();
}, building: true);
assert(_dirtyElements.isEmpty);
Timeline.finishSync();
}
/// The [Element] that is at the root of the hierarchy (and which wraps the