From e8a3a0b90c76ac4beb03721b477c3b2817afe852 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Tue, 12 Jan 2016 22:18:58 -0800 Subject: [PATCH] Move //sky/compositor to //flow Now that the compositor doesn't have any tricky deps, we can make it a top-level project, which saves a bunch of typing. --- engine/src/flutter/flow/BUILD.gn | 45 ++++++ engine/src/flutter/flow/README.md | 6 + engine/src/flutter/flow/checkerboard.cc | 45 ++++++ engine/src/flutter/flow/checkerboard.h | 16 ++ engine/src/flutter/flow/clip_path_layer.cc | 23 +++ engine/src/flutter/flow/clip_path_layer.h | 30 ++++ engine/src/flutter/flow/clip_rect_layer.cc | 22 +++ engine/src/flutter/flow/clip_rect_layer.h | 30 ++++ engine/src/flutter/flow/clip_rrect_layer.cc | 23 +++ engine/src/flutter/flow/clip_rrect_layer.h | 29 ++++ engine/src/flutter/flow/color_filter_layer.cc | 32 ++++ engine/src/flutter/flow/color_filter_layer.h | 36 +++++ engine/src/flutter/flow/container_layer.cc | 40 +++++ engine/src/flutter/flow/container_layer.h | 35 +++++ engine/src/flutter/flow/instrumentation.cc | 140 ++++++++++++++++++ engine/src/flutter/flow/instrumentation.h | 76 ++++++++++ engine/src/flutter/flow/layer.cc | 23 +++ engine/src/flutter/flow/layer.h | 67 +++++++++ engine/src/flutter/flow/layer_tree.cc | 31 ++++ engine/src/flutter/flow/layer_tree.h | 66 +++++++++ engine/src/flutter/flow/opacity_layer.cc | 31 ++++ engine/src/flutter/flow/opacity_layer.h | 31 ++++ engine/src/flutter/flow/paint_context.cc | 52 +++++++ engine/src/flutter/flow/paint_context.h | 74 +++++++++ .../flutter/flow/performance_overlay_layer.cc | 79 ++++++++++ .../flutter/flow/performance_overlay_layer.h | 32 ++++ engine/src/flutter/flow/picture_layer.cc | 45 ++++++ engine/src/flutter/flow/picture_layer.h | 38 +++++ engine/src/flutter/flow/raster_cache.cc | 114 ++++++++++++++ engine/src/flutter/flow/raster_cache.h | 47 ++++++ engine/src/flutter/flow/shader_mask_layer.cc | 33 +++++ engine/src/flutter/flow/shader_mask_layer.h | 43 ++++++ engine/src/flutter/flow/transform_layer.cc | 29 ++++ engine/src/flutter/flow/transform_layer.h | 30 ++++ 34 files changed, 1493 insertions(+) create mode 100644 engine/src/flutter/flow/BUILD.gn create mode 100644 engine/src/flutter/flow/README.md create mode 100644 engine/src/flutter/flow/checkerboard.cc create mode 100644 engine/src/flutter/flow/checkerboard.h create mode 100644 engine/src/flutter/flow/clip_path_layer.cc create mode 100644 engine/src/flutter/flow/clip_path_layer.h create mode 100644 engine/src/flutter/flow/clip_rect_layer.cc create mode 100644 engine/src/flutter/flow/clip_rect_layer.h create mode 100644 engine/src/flutter/flow/clip_rrect_layer.cc create mode 100644 engine/src/flutter/flow/clip_rrect_layer.h create mode 100644 engine/src/flutter/flow/color_filter_layer.cc create mode 100644 engine/src/flutter/flow/color_filter_layer.h create mode 100644 engine/src/flutter/flow/container_layer.cc create mode 100644 engine/src/flutter/flow/container_layer.h create mode 100644 engine/src/flutter/flow/instrumentation.cc create mode 100644 engine/src/flutter/flow/instrumentation.h create mode 100644 engine/src/flutter/flow/layer.cc create mode 100644 engine/src/flutter/flow/layer.h create mode 100644 engine/src/flutter/flow/layer_tree.cc create mode 100644 engine/src/flutter/flow/layer_tree.h create mode 100644 engine/src/flutter/flow/opacity_layer.cc create mode 100644 engine/src/flutter/flow/opacity_layer.h create mode 100644 engine/src/flutter/flow/paint_context.cc create mode 100644 engine/src/flutter/flow/paint_context.h create mode 100644 engine/src/flutter/flow/performance_overlay_layer.cc create mode 100644 engine/src/flutter/flow/performance_overlay_layer.h create mode 100644 engine/src/flutter/flow/picture_layer.cc create mode 100644 engine/src/flutter/flow/picture_layer.h create mode 100644 engine/src/flutter/flow/raster_cache.cc create mode 100644 engine/src/flutter/flow/raster_cache.h create mode 100644 engine/src/flutter/flow/shader_mask_layer.cc create mode 100644 engine/src/flutter/flow/shader_mask_layer.h create mode 100644 engine/src/flutter/flow/transform_layer.cc create mode 100644 engine/src/flutter/flow/transform_layer.h diff --git a/engine/src/flutter/flow/BUILD.gn b/engine/src/flutter/flow/BUILD.gn new file mode 100644 index 00000000000..f6555a6e688 --- /dev/null +++ b/engine/src/flutter/flow/BUILD.gn @@ -0,0 +1,45 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("flow") { + sources = [ + "checkerboard.cc", + "checkerboard.h", + "clip_path_layer.cc", + "clip_path_layer.h", + "clip_rect_layer.cc", + "clip_rect_layer.h", + "clip_rrect_layer.cc", + "clip_rrect_layer.h", + "color_filter_layer.cc", + "color_filter_layer.h", + "container_layer.cc", + "container_layer.h", + "instrumentation.cc", + "instrumentation.h", + "layer.cc", + "layer.h", + "layer_tree.cc", + "layer_tree.h", + "opacity_layer.cc", + "opacity_layer.h", + "paint_context.cc", + "paint_context.h", + "picture_layer.cc", + "picture_layer.h", + "raster_cache.cc", + "raster_cache.h", + "performance_overlay_layer.cc", + "performance_overlay_layer.h", + "shader_mask_layer.cc", + "shader_mask_layer.h", + "transform_layer.cc", + "transform_layer.h", + ] + + deps = [ + "//base", + "//skia", + ] +} diff --git a/engine/src/flutter/flow/README.md b/engine/src/flutter/flow/README.md new file mode 100644 index 00000000000..a0a37a03d58 --- /dev/null +++ b/engine/src/flutter/flow/README.md @@ -0,0 +1,6 @@ +Flow +==== + +Flow is a simple compositor based on Skia that the Flutter engine uses to cache +recoded paint commands and pixels generated from those recordings. Flow runs on +the GPU thread and uploads information to the GPU. diff --git a/engine/src/flutter/flow/checkerboard.cc b/engine/src/flutter/flow/checkerboard.cc new file mode 100644 index 00000000000..2a3b0e48f48 --- /dev/null +++ b/engine/src/flutter/flow/checkerboard.cc @@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/checkerboard.h" + +#include "third_party/skia/include/core/SkShader.h" + +namespace flow { + +static SkShader* CreateCheckerboardShader(SkColor c1, SkColor c2, int size) { + SkBitmap bm; + bm.allocN32Pixels(2 * size, 2 * size); + bm.eraseColor(c1); + bm.eraseArea(SkIRect::MakeLTRB(0, 0, size, size), c2); + bm.eraseArea(SkIRect::MakeLTRB(size, size, 2 * size, 2 * size), c2); + return SkShader::CreateBitmapShader(bm, SkShader::kRepeat_TileMode, + SkShader::kRepeat_TileMode); +} + +static void DrawCheckerboard(SkCanvas* canvas, + SkColor c1, + SkColor c2, + int size) { + SkPaint paint; + paint.setShader(CreateCheckerboardShader(c1, c2, size))->unref(); + canvas->drawPaint(paint); +} + +void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect) { + // Draw a checkerboard + canvas->save(); + canvas->clipRect(rect); + DrawCheckerboard(canvas, 0x4400FF00, 0x00000000, 12); + canvas->restore(); + + // Stroke the drawn area + SkPaint debugPaint; + debugPaint.setStrokeWidth(3); + debugPaint.setColor(SK_ColorRED); + debugPaint.setStyle(SkPaint::kStroke_Style); + canvas->drawRect(rect, debugPaint); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/checkerboard.h b/engine/src/flutter/flow/checkerboard.h new file mode 100644 index 00000000000..1107171a77a --- /dev/null +++ b/engine/src/flutter/flow/checkerboard.h @@ -0,0 +1,16 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_CHECKERBOARD_H_ +#define FLOW_CHECKERBOARD_H_ + +#include "third_party/skia/include/core/SkCanvas.h" + +namespace flow { + +void DrawCheckerboard(SkCanvas* canvas, const SkRect& rect); + +} // namespace flow + +#endif // FLOW_CHECKERBOARD_H_ diff --git a/engine/src/flutter/flow/clip_path_layer.cc b/engine/src/flutter/flow/clip_path_layer.cc new file mode 100644 index 00000000000..306ca5f2399 --- /dev/null +++ b/engine/src/flutter/flow/clip_path_layer.cc @@ -0,0 +1,23 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/clip_path_layer.h" + +namespace flow { + +ClipPathLayer::ClipPathLayer() { +} + +ClipPathLayer::~ClipPathLayer() { +} + +void ClipPathLayer::Paint(PaintContext::ScopedFrame& frame) { + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, false); + canvas.saveLayer(&clip_path_.getBounds(), nullptr); + canvas.clipPath(clip_path_); + PaintChildren(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/clip_path_layer.h b/engine/src/flutter/flow/clip_path_layer.h new file mode 100644 index 00000000000..6fd3a81021f --- /dev/null +++ b/engine/src/flutter/flow/clip_path_layer.h @@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_CLIP_PATH_LAYER_H_ +#define FLOW_CLIP_PATH_LAYER_H_ + +#include "flow/container_layer.h" + +namespace flow { + +class ClipPathLayer : public ContainerLayer { + public: + ClipPathLayer(); + ~ClipPathLayer() override; + + void set_clip_path(const SkPath& clip_path) { clip_path_ = clip_path; } + + protected: + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + SkPath clip_path_; + + DISALLOW_COPY_AND_ASSIGN(ClipPathLayer); +}; + +} // namespace flow + +#endif // FLOW_CLIP_PATH_LAYER_H_ diff --git a/engine/src/flutter/flow/clip_rect_layer.cc b/engine/src/flutter/flow/clip_rect_layer.cc new file mode 100644 index 00000000000..90475b3b41f --- /dev/null +++ b/engine/src/flutter/flow/clip_rect_layer.cc @@ -0,0 +1,22 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/clip_rect_layer.h" + +namespace flow { + +ClipRectLayer::ClipRectLayer() { +} + +ClipRectLayer::~ClipRectLayer() { +} + +void ClipRectLayer::Paint(PaintContext::ScopedFrame& frame) { + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, true); + canvas.clipRect(clip_rect_); + PaintChildren(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/clip_rect_layer.h b/engine/src/flutter/flow/clip_rect_layer.h new file mode 100644 index 00000000000..33761dd0343 --- /dev/null +++ b/engine/src/flutter/flow/clip_rect_layer.h @@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_CLIP_RECT_LAYER_H_ +#define FLOW_CLIP_RECT_LAYER_H_ + +#include "flow/container_layer.h" + +namespace flow { + +class ClipRectLayer : public ContainerLayer { + public: + ClipRectLayer(); + ~ClipRectLayer() override; + + void set_clip_rect(const SkRect& clip_rect) { clip_rect_ = clip_rect; } + + protected: + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + SkRect clip_rect_; + + DISALLOW_COPY_AND_ASSIGN(ClipRectLayer); +}; + +} // namespace flow + +#endif // FLOW_CLIP_RECT_LAYER_H_ diff --git a/engine/src/flutter/flow/clip_rrect_layer.cc b/engine/src/flutter/flow/clip_rrect_layer.cc new file mode 100644 index 00000000000..3b184b44a0d --- /dev/null +++ b/engine/src/flutter/flow/clip_rrect_layer.cc @@ -0,0 +1,23 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/clip_rrect_layer.h" + +namespace flow { + +ClipRRectLayer::ClipRRectLayer() { +} + +ClipRRectLayer::~ClipRRectLayer() { +} + +void ClipRRectLayer::Paint(PaintContext::ScopedFrame& frame) { + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, false); + canvas.saveLayer(&clip_rrect_.getBounds(), nullptr); + canvas.clipRRect(clip_rrect_); + PaintChildren(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/clip_rrect_layer.h b/engine/src/flutter/flow/clip_rrect_layer.h new file mode 100644 index 00000000000..20bb4a6d732 --- /dev/null +++ b/engine/src/flutter/flow/clip_rrect_layer.h @@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_CLIP_RRECT_LAYER_H_ +#define FLOW_CLIP_RRECT_LAYER_H_ + +#include "flow/container_layer.h" + +namespace flow { + +class ClipRRectLayer : public ContainerLayer { + public: + ClipRRectLayer(); + ~ClipRRectLayer() override; + + void set_clip_rrect(const SkRRect& clip_rrect) { clip_rrect_ = clip_rrect; } + + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + SkRRect clip_rrect_; + + DISALLOW_COPY_AND_ASSIGN(ClipRRectLayer); +}; + +} // namespace flow + +#endif // FLOW_CLIP_RRECT_LAYER_H_ diff --git a/engine/src/flutter/flow/color_filter_layer.cc b/engine/src/flutter/flow/color_filter_layer.cc new file mode 100644 index 00000000000..d67d1281ac8 --- /dev/null +++ b/engine/src/flutter/flow/color_filter_layer.cc @@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/color_filter_layer.h" + +namespace flow { + +ColorFilterLayer::ColorFilterLayer() { +} + +ColorFilterLayer::~ColorFilterLayer() { +} + +void ColorFilterLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + ContainerLayer::Preroll(context, matrix); + set_paint_bounds(context->child_paint_bounds); +} + +void ColorFilterLayer::Paint(PaintContext::ScopedFrame& frame) { + skia::RefPtr color_filter = + skia::AdoptRef(SkColorFilter::CreateModeFilter(color_, transfer_mode_)); + SkPaint paint; + paint.setColorFilter(color_filter.get()); + + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, false); + canvas.saveLayer(&paint_bounds(), &paint); + PaintChildren(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/color_filter_layer.h b/engine/src/flutter/flow/color_filter_layer.h new file mode 100644 index 00000000000..37de5f71721 --- /dev/null +++ b/engine/src/flutter/flow/color_filter_layer.h @@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_COLOR_FILTER_LAYER_H_ +#define FLOW_COLOR_FILTER_LAYER_H_ + +#include "flow/container_layer.h" + +namespace flow { + +class ColorFilterLayer : public ContainerLayer { + public: + ColorFilterLayer(); + ~ColorFilterLayer() override; + + void set_color(SkColor color) { color_ = color; } + + void set_transfer_mode(SkXfermode::Mode transfer_mode) { + transfer_mode_ = transfer_mode; + } + + protected: + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + SkColor color_; + SkXfermode::Mode transfer_mode_; + + DISALLOW_COPY_AND_ASSIGN(ColorFilterLayer); +}; + +} // namespace flow + +#endif // FLOW_COLOR_FILTER_LAYER_H_ diff --git a/engine/src/flutter/flow/container_layer.cc b/engine/src/flutter/flow/container_layer.cc new file mode 100644 index 00000000000..c90ca79b068 --- /dev/null +++ b/engine/src/flutter/flow/container_layer.cc @@ -0,0 +1,40 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/container_layer.h" + +namespace flow { + +ContainerLayer::ContainerLayer() { +} + +ContainerLayer::~ContainerLayer() { +} + +void ContainerLayer::Add(std::unique_ptr layer) { + layer->set_parent(this); + layers_.push_back(std::move(layer)); +} + +void ContainerLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + PrerollChildren(context, matrix); +} + +void ContainerLayer::PrerollChildren(PrerollContext* context, + const SkMatrix& matrix) { + SkRect child_paint_bounds; + for (auto& layer : layers_) { + PrerollContext child_context = *context; + layer->Preroll(&child_context, matrix); + child_paint_bounds.join(child_context.child_paint_bounds); + } + context->child_paint_bounds = child_paint_bounds; +} + +void ContainerLayer::PaintChildren(PaintContext::ScopedFrame& frame) const { + for (auto& layer : layers_) + layer->Paint(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/container_layer.h b/engine/src/flutter/flow/container_layer.h new file mode 100644 index 00000000000..e1f0bca43c6 --- /dev/null +++ b/engine/src/flutter/flow/container_layer.h @@ -0,0 +1,35 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_CONTAINER_LAYER_H_ +#define FLOW_CONTAINER_LAYER_H_ + +#include +#include "flow/layer.h" + +namespace flow { + +class ContainerLayer : public Layer { + public: + ContainerLayer(); + ~ContainerLayer() override; + + void Add(std::unique_ptr layer); + + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void PrerollChildren(PrerollContext* context, const SkMatrix& matrix); + + void PaintChildren(PaintContext::ScopedFrame& frame) const; + + const std::vector>& layers() const { return layers_; } + + private: + std::vector> layers_; + + DISALLOW_COPY_AND_ASSIGN(ContainerLayer); +}; + +} // namespace flow + +#endif // FLOW_CONTAINER_LAYER_H_ diff --git a/engine/src/flutter/flow/instrumentation.cc b/engine/src/flutter/flow/instrumentation.cc new file mode 100644 index 00000000000..da4a47aeead --- /dev/null +++ b/engine/src/flutter/flow/instrumentation.cc @@ -0,0 +1,140 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/instrumentation.h" + +#include + +#include "third_party/skia/include/core/SkPath.h" + +namespace flow { +namespace instrumentation { + +static const size_t kMaxSamples = 120; +static const size_t kMaxFrameMarkers = 8; +static const double kOneFrameMS = 1e3 / 60.0; + +Stopwatch::Stopwatch() : _start(base::TimeTicks::Now()), _current_sample(0) { + const base::TimeDelta delta; + _laps.resize(kMaxSamples, delta); +} + +void Stopwatch::start() { + _start = base::TimeTicks::Now(); + _current_sample = (_current_sample + 1) % kMaxSamples; +} + +void Stopwatch::stop() { + _laps[_current_sample] = base::TimeTicks::Now() - _start; +} + +void Stopwatch::setLapTime(const base::TimeDelta& delta) { + _current_sample = (_current_sample + 1) % kMaxSamples; + _laps[_current_sample] = delta; +} + +const base::TimeDelta& Stopwatch::lastLap() const { + return _laps[(_current_sample - 1) % kMaxSamples]; +} + +static inline constexpr double UnitFrameInterval(double frameTimeMS) { + return frameTimeMS * 60.0 * 1e-3; +} + +base::TimeDelta Stopwatch::maxDelta() const { + base::TimeDelta maxDelta; + for (size_t i = 0; i < kMaxSamples; i++) { + if (_laps[i] > maxDelta) { + maxDelta = _laps[i]; + } + } + return maxDelta; +} + +void Stopwatch::visualize(SkCanvas& canvas, const SkRect& rect) const { + SkPaint paint; + + // Paint the background + paint.setColor(0xAAFFFFFF); + canvas.drawRect(rect, paint); + + // Paint the graph + SkPath path; + const SkScalar width = rect.width(); + const SkScalar height = rect.height(); + + // Find the max delta. We use this to scale the graph + + double maxInterval = maxDelta().InMillisecondsF(); + + if (maxInterval < kOneFrameMS) { + maxInterval = kOneFrameMS; + } else { + maxInterval = + kOneFrameMS * (static_cast(maxInterval / kOneFrameMS) + 1); + } + + const double maxUnitInterval = UnitFrameInterval(maxInterval); + + // Draw the path + double unitHeight = + UnitFrameInterval(_laps[0].InMillisecondsF()) / maxUnitInterval; + + path.moveTo(0, height); + path.lineTo(0, height * (1.0 - unitHeight)); + + for (size_t i = 0; i < kMaxSamples; i++) { + double unitWidth = (static_cast(i + 1) / kMaxSamples); + unitHeight = + UnitFrameInterval(_laps[i].InMillisecondsF()) / maxUnitInterval; + path.lineTo(width * unitWidth, height * (1.0 - unitHeight)); + } + + path.lineTo(width, height); + + path.close(); + + paint.setColor(0xAA0000FF); + canvas.drawPath(path, paint); + + paint.setStrokeWidth(1); + paint.setStyle(SkPaint::Style::kStroke_Style); + paint.setColor(0xAAFFFFFF); + + if (maxInterval > kOneFrameMS) { + // Paint the horizontal markers + size_t frameMarkerCount = static_cast(maxInterval / kOneFrameMS); + + // Limit the number of markers displayed. After a certain point, the graph + // becomes crowded + if (frameMarkerCount > kMaxFrameMarkers) { + frameMarkerCount = 1; + } + + for (size_t frameIndex = 0; frameIndex < frameMarkerCount; frameIndex++) { + const double frameHeight = + height * (1.0 - (UnitFrameInterval((frameIndex + 1) * kOneFrameMS) / + maxUnitInterval)); + canvas.drawLine(0, frameHeight, width, frameHeight, paint); + } + } + + // Paint the vertical marker + if (UnitFrameInterval(lastLap().InMillisecondsF()) > 1.0) { + // budget exceeded + paint.setColor(SK_ColorRED); + } else { + // within budget + paint.setColor(SK_ColorGREEN); + } + + double sampleX = width * (static_cast(_current_sample) / kMaxSamples); + paint.setStrokeWidth(3); + canvas.drawLine(sampleX, 0, sampleX, height, paint); +} + +Stopwatch::~Stopwatch() = default; + +} // namespace instrumentation +} // namespace flow diff --git a/engine/src/flutter/flow/instrumentation.h b/engine/src/flutter/flow/instrumentation.h new file mode 100644 index 00000000000..164b5e9cef3 --- /dev/null +++ b/engine/src/flutter/flow/instrumentation.h @@ -0,0 +1,76 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_INSTRUMENTATION_H_ +#define FLOW_INSTRUMENTATION_H_ + +#include +#include "base/macros.h" +#include "base/time/time.h" +#include "third_party/skia/include/core/SkCanvas.h" + +namespace flow { +namespace instrumentation { + +class Stopwatch { + public: + class ScopedLap { + public: + explicit ScopedLap(Stopwatch& stopwatch) : _stopwatch(stopwatch) { + _stopwatch.start(); + } + + ~ScopedLap() { _stopwatch.stop(); } + + private: + Stopwatch& _stopwatch; + + DISALLOW_COPY_AND_ASSIGN(ScopedLap); + }; + + explicit Stopwatch(); + ~Stopwatch(); + + const base::TimeDelta& lastLap() const; + + base::TimeDelta currentLap() const { return base::TimeTicks::Now() - _start; } + + void visualize(SkCanvas& canvas, const SkRect& rect) const; + + void start(); + + void stop(); + + void setLapTime(const base::TimeDelta& delta); + + private: + base::TimeTicks _start; + std::vector _laps; + size_t _current_sample; + + base::TimeDelta maxDelta() const; + + DISALLOW_COPY_AND_ASSIGN(Stopwatch); +}; + +class Counter { + public: + explicit Counter() : _count(0) {} + + size_t count() const { return _count; } + + void reset(size_t count = 0) { _count = count; } + + void increment(size_t count = 1) { _count += count; } + + private: + size_t _count; + + DISALLOW_COPY_AND_ASSIGN(Counter); +}; + +} // namespace instrumentation +} // namespace flow + +#endif // FLOW_INSTRUMENTATION_H_ diff --git a/engine/src/flutter/flow/layer.cc b/engine/src/flutter/flow/layer.cc new file mode 100644 index 00000000000..748db663499 --- /dev/null +++ b/engine/src/flutter/flow/layer.cc @@ -0,0 +1,23 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/layer.h" + +#include "third_party/skia/include/core/SkColorFilter.h" + +namespace flow { + +Layer::Layer() + : parent_(nullptr) + , has_paint_bounds_(false) + , paint_bounds_() { +} + +Layer::~Layer() { +} + +void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) { +} + +} // namespace flow diff --git a/engine/src/flutter/flow/layer.h b/engine/src/flutter/flow/layer.h new file mode 100644 index 00000000000..a8ec2bb4cec --- /dev/null +++ b/engine/src/flutter/flow/layer.h @@ -0,0 +1,67 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_LAYER_H_ +#define FLOW_LAYER_H_ + +#include +#include + +#include "base/logging.h" +#include "base/macros.h" +#include "skia/ext/refptr.h" +#include "flow/paint_context.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" +#include "third_party/skia/include/core/SkColorFilter.h" +#include "third_party/skia/include/core/SkMatrix.h" +#include "third_party/skia/include/core/SkPath.h" +#include "third_party/skia/include/core/SkPicture.h" +#include "third_party/skia/include/core/SkRect.h" +#include "third_party/skia/include/core/SkRRect.h" +#include "third_party/skia/include/core/SkXfermode.h" + +namespace flow { + +class ContainerLayer; +class Layer { + public: + Layer(); + virtual ~Layer(); + + struct PrerollContext { + PaintContext::ScopedFrame& frame; + SkRect child_paint_bounds; + }; + + virtual void Preroll(PrerollContext* context, const SkMatrix& matrix); + virtual void Paint(PaintContext::ScopedFrame& frame) = 0; + + ContainerLayer* parent() const { return parent_; } + + void set_parent(ContainerLayer* parent) { parent_ = parent; } + + const bool has_paint_bounds() const { return has_paint_bounds_; } + + const SkRect& paint_bounds() const { + DCHECK(has_paint_bounds_); + return paint_bounds_; + } + + void set_paint_bounds(const SkRect& paint_bounds) { + has_paint_bounds_ = true; + paint_bounds_ = paint_bounds; + } + + private: + ContainerLayer* parent_; + bool has_paint_bounds_; // if false, paint_bounds_ is not valid + SkRect paint_bounds_; + + DISALLOW_COPY_AND_ASSIGN(Layer); +}; + +} // namespace flow + +#endif // FLOW_LAYER_H_ diff --git a/engine/src/flutter/flow/layer_tree.cc b/engine/src/flutter/flow/layer_tree.cc new file mode 100644 index 00000000000..1173038f8fe --- /dev/null +++ b/engine/src/flutter/flow/layer_tree.cc @@ -0,0 +1,31 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/layer_tree.h" + +#include "base/trace_event/trace_event.h" +#include "flow/layer.h" + +namespace flow { + +LayerTree::LayerTree() : rasterizer_tracing_threashold_(0) { +} + +LayerTree::~LayerTree() { +} + +void LayerTree::Raster(PaintContext::ScopedFrame& frame) { + { + TRACE_EVENT0("flutter", "LayerTree::Preroll") + Layer::PrerollContext context = { frame, SkRect::MakeEmpty() }; + root_layer_->Preroll(&context, SkMatrix()); + } + + { + TRACE_EVENT0("flutter", "LayerTree::Paint") + root_layer_->Paint(frame); + } +} + +} // namespace flow diff --git a/engine/src/flutter/flow/layer_tree.h b/engine/src/flutter/flow/layer_tree.h new file mode 100644 index 00000000000..d1e71bbfc28 --- /dev/null +++ b/engine/src/flutter/flow/layer_tree.h @@ -0,0 +1,66 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_LAYER_TREE_H_ +#define FLOW_LAYER_TREE_H_ + +#include +#include + +#include "base/macros.h" +#include "base/time/time.h" +#include "flow/layer.h" +#include "third_party/skia/include/core/SkSize.h" + +namespace flow { + +class LayerTree { + public: + LayerTree(); + ~LayerTree(); + + void Raster(PaintContext::ScopedFrame& frame); + + Layer* root_layer() const { return root_layer_.get(); } + + void set_root_layer(std::unique_ptr root_layer) { + root_layer_ = std::move(root_layer); + } + + const SkISize& frame_size() const { return frame_size_; } + + void set_frame_size(const SkISize& frame_size) { frame_size_ = frame_size; } + + void set_construction_time(const base::TimeDelta& delta) { + construction_time_ = delta; + } + + const base::TimeDelta& construction_time() const { + return construction_time_; + } + + // The number of frame intervals missed after which the compositor must + // trace the rasterized picture to a trace file. Specify 0 to disable all + // tracing + void set_rasterizer_tracing_threshold(uint32_t interval) { + rasterizer_tracing_threashold_ = interval; + } + + uint32_t rasterizer_tracing_threshold() const { + return rasterizer_tracing_threashold_; + } + + private: + SkISize frame_size_; // Physical pixels. + std::unique_ptr root_layer_; + + base::TimeDelta construction_time_; + uint32_t rasterizer_tracing_threashold_; + + DISALLOW_COPY_AND_ASSIGN(LayerTree); +}; + +} // namespace flow + +#endif // FLOW_LAYER_TREE_H_ diff --git a/engine/src/flutter/flow/opacity_layer.cc b/engine/src/flutter/flow/opacity_layer.cc new file mode 100644 index 00000000000..6ecedd9770c --- /dev/null +++ b/engine/src/flutter/flow/opacity_layer.cc @@ -0,0 +1,31 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/opacity_layer.h" + +namespace flow { + +OpacityLayer::OpacityLayer() { +} + +OpacityLayer::~OpacityLayer() { +} + +void OpacityLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + ContainerLayer::Preroll(context, matrix); + set_paint_bounds(context->child_paint_bounds); +} + +void OpacityLayer::Paint(PaintContext::ScopedFrame& frame) { + SkPaint paint; + paint.setColor(SkColorSetARGB(alpha_, 0, 0, 0)); + paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); + + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, false); + canvas.saveLayer(&paint_bounds(), &paint); + PaintChildren(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/opacity_layer.h b/engine/src/flutter/flow/opacity_layer.h new file mode 100644 index 00000000000..2435333b854 --- /dev/null +++ b/engine/src/flutter/flow/opacity_layer.h @@ -0,0 +1,31 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_OPACITY_LAYER_H_ +#define FLOW_OPACITY_LAYER_H_ + +#include "flow/container_layer.h" + +namespace flow { + +class OpacityLayer : public ContainerLayer { + public: + OpacityLayer(); + ~OpacityLayer() override; + + void set_alpha(int alpha) { alpha_ = alpha; } + + protected: + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + int alpha_; + + DISALLOW_COPY_AND_ASSIGN(OpacityLayer); +}; + +} // namespace flow + +#endif // FLOW_OPACITY_LAYER_H_ diff --git a/engine/src/flutter/flow/paint_context.cc b/engine/src/flutter/flow/paint_context.cc new file mode 100644 index 00000000000..ffa4b7c5f6b --- /dev/null +++ b/engine/src/flutter/flow/paint_context.cc @@ -0,0 +1,52 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/paint_context.h" + +#include "base/logging.h" +#include "third_party/skia/include/core/SkCanvas.h" + +namespace flow { + +PaintContext::PaintContext() { +} + +void PaintContext::beginFrame(ScopedFrame& frame, bool enableInstrumentation) { + if (enableInstrumentation) { + frame_count_.increment(); + frame_time_.start(); + } +} + +void PaintContext::endFrame(ScopedFrame& frame, bool enableInstrumentation) { + raster_cache_.SweepAfterFrame(); + if (enableInstrumentation) { + frame_time_.stop(); + } +} + +PaintContext::ScopedFrame PaintContext::AcquireFrame( + GrContext* gr_context, SkCanvas& canvas, bool instrumentation_enabled) { + return ScopedFrame(*this, gr_context, canvas, instrumentation_enabled); +} + +PaintContext::ScopedFrame::ScopedFrame(PaintContext& context, + GrContext* gr_context, + SkCanvas& canvas, + bool instrumentation_enabled) + : context_(context), gr_context_(gr_context), canvas_(&canvas), + instrumentation_enabled_(instrumentation_enabled) { + context_.beginFrame(*this, instrumentation_enabled_); +} + +PaintContext::ScopedFrame::ScopedFrame(ScopedFrame&& frame) = default; + +PaintContext::ScopedFrame::~ScopedFrame() { + context_.endFrame(*this, instrumentation_enabled_); +} + +PaintContext::~PaintContext() { +} + +} // namespace flow diff --git a/engine/src/flutter/flow/paint_context.h b/engine/src/flutter/flow/paint_context.h new file mode 100644 index 00000000000..e0fb8faded7 --- /dev/null +++ b/engine/src/flutter/flow/paint_context.h @@ -0,0 +1,74 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_PAINT_CONTEXT_H_ +#define FLOW_PAINT_CONTEXT_H_ + +#include +#include + +#include "base/macros.h" +#include "base/logging.h" +#include "flow/instrumentation.h" +#include "flow/raster_cache.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPictureRecorder.h" + +namespace flow { + +class PaintContext { + public: + class ScopedFrame { + public: + SkCanvas& canvas() { return *canvas_; } + PaintContext& context() const { return context_; } + GrContext* gr_context() const { return gr_context_; } + + ScopedFrame(ScopedFrame&& frame); + ~ScopedFrame(); + + private: + PaintContext& context_; + GrContext* gr_context_; + SkCanvas* canvas_; + const bool instrumentation_enabled_; + + ScopedFrame(PaintContext& context, + GrContext* gr_context, + SkCanvas& canvas, + bool instrumentation_enabled); + + friend class PaintContext; + + DISALLOW_COPY_AND_ASSIGN(ScopedFrame); + }; + + PaintContext(); + ~PaintContext(); + + ScopedFrame AcquireFrame(GrContext* gr_context, + SkCanvas& canvas, + bool instrumentation_enabled = true); + + RasterCache& raster_cache() { return raster_cache_; } + const instrumentation::Counter& frame_count() const { return frame_count_; } + const instrumentation::Stopwatch& frame_time() const { return frame_time_; } + instrumentation::Stopwatch& engine_time() { return engine_time_; }; + + private: + RasterCache raster_cache_; + + instrumentation::Counter frame_count_; + instrumentation::Stopwatch frame_time_; + instrumentation::Stopwatch engine_time_; + + void beginFrame(ScopedFrame& frame, bool enableInstrumentation); + void endFrame(ScopedFrame& frame, bool enableInstrumentation); + + DISALLOW_COPY_AND_ASSIGN(PaintContext); +}; + +} // namespace flow + +#endif // FLOW_PAINT_CONTEXT_H_ diff --git a/engine/src/flutter/flow/performance_overlay_layer.cc b/engine/src/flutter/flow/performance_overlay_layer.cc new file mode 100644 index 00000000000..93d328968a2 --- /dev/null +++ b/engine/src/flutter/flow/performance_overlay_layer.cc @@ -0,0 +1,79 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include + +#include "flow/performance_overlay_layer.h" + +namespace flow { + +PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t enabledOptions) + : options_(enabledOptions) { +} + +static void DrawStatisticsText(SkCanvas& canvas, + const std::string& string, + int x, + int y) { + SkPaint paint; + paint.setTextSize(14); + paint.setLinearText(false); + paint.setColor(SK_ColorRED); + canvas.drawText(string.c_str(), string.size(), x, y, paint); +} + +static void VisualizeStopWatch(SkCanvas& canvas, + const instrumentation::Stopwatch& stopwatch, + SkScalar width, + bool show_graph, + bool show_labels, + std::string label_prefix) { + const int x = 8; + const int y = 70; + const int height = 80; + + if (show_graph) { + SkRect visualizationRect = SkRect::MakeWH(width, height); + stopwatch.visualize(canvas, visualizationRect); + } + + if (show_labels) { + double msPerFrame = stopwatch.lastLap().InMillisecondsF(); + double fps = 1e3 / msPerFrame; + + std::stringstream stream; + stream.setf(std::ios::fixed | std::ios::showpoint); + stream << std::setprecision(2); + stream << label_prefix << " " << fps << " FPS | " << msPerFrame + << "ms/frame"; + DrawStatisticsText(canvas, stream.str(), x, y); + } + + if (show_labels || show_graph) { + canvas.translate(0, height); + } +} + +void PerformanceOverlayLayer::Paint(PaintContext::ScopedFrame& frame) { + if (!options_) { + return; + } + + SkScalar width = has_paint_bounds() ? paint_bounds().width() : 0; + SkAutoCanvasRestore save(&frame.canvas(), true); + + VisualizeStopWatch(frame.canvas(), frame.context().frame_time(), width, + options_ & kVisualizeRasterizerStatistics, + options_ & kDisplayRasterizerStatistics, + "Rasterizer"); + + VisualizeStopWatch(frame.canvas(), frame.context().engine_time(), width, + options_ & kVisualizeEngineStatistics, + options_ & kDisplayEngineStatistics, + "Engine"); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/performance_overlay_layer.h b/engine/src/flutter/flow/performance_overlay_layer.h new file mode 100644 index 00000000000..23ca34e1380 --- /dev/null +++ b/engine/src/flutter/flow/performance_overlay_layer.h @@ -0,0 +1,32 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_PERFORMANCE_OVERLAY_LAYER_H_ +#define FLOW_PERFORMANCE_OVERLAY_LAYER_H_ + +#include "base/macros.h" +#include "flow/layer.h" + +namespace flow { + +const int kDisplayRasterizerStatistics = 0x01; +const int kVisualizeRasterizerStatistics = 0x02; +const int kDisplayEngineStatistics = 0x04; +const int kVisualizeEngineStatistics = 0x08; + +class PerformanceOverlayLayer : public Layer { + public: + explicit PerformanceOverlayLayer(uint64_t enabledOptions); + + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + int options_; + + DISALLOW_COPY_AND_ASSIGN(PerformanceOverlayLayer); +}; + +} // namespace flow + +#endif // FLOW_PERFORMANCE_OVERLAY_LAYER_H_ diff --git a/engine/src/flutter/flow/picture_layer.cc b/engine/src/flutter/flow/picture_layer.cc new file mode 100644 index 00000000000..9bca05c7bfc --- /dev/null +++ b/engine/src/flutter/flow/picture_layer.cc @@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/picture_layer.h" + +#include "base/logging.h" +#include "flow/checkerboard.h" +#include "flow/raster_cache.h" + +namespace flow { + +// TODO(abarth): Make this configurable by developers. +const bool kDebugCheckerboardRasterizedLayers = false; + +PictureLayer::PictureLayer() { +} + +PictureLayer::~PictureLayer() { +} + +void PictureLayer::Preroll(PrerollContext* context, + const SkMatrix& matrix) { + image_ = context->frame.context().raster_cache().GetPrerolledImage( + context->frame.gr_context(), picture_.get(), matrix); + context->child_paint_bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); +} + +void PictureLayer::Paint(PaintContext::ScopedFrame& frame) { + DCHECK(picture_); + + SkCanvas& canvas = frame.canvas(); + if (image_) { + SkRect rect = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); + canvas.drawImageRect(image_.get(), rect, nullptr, SkCanvas::kFast_SrcRectConstraint); + if (kDebugCheckerboardRasterizedLayers) + DrawCheckerboard(&canvas, rect); + } else { + SkAutoCanvasRestore save(&canvas, true); + canvas.translate(offset_.x(), offset_.y()); + canvas.drawPicture(picture_.get()); + } +} + +} // namespace flow diff --git a/engine/src/flutter/flow/picture_layer.h b/engine/src/flutter/flow/picture_layer.h new file mode 100644 index 00000000000..c1fd3b35e9e --- /dev/null +++ b/engine/src/flutter/flow/picture_layer.h @@ -0,0 +1,38 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_PICTURE_LAYER_H_ +#define FLOW_PICTURE_LAYER_H_ + +#include "flow/layer.h" + +namespace flow { + +class PictureLayer : public Layer { + public: + PictureLayer(); + ~PictureLayer() override; + + void set_offset(const SkPoint& offset) { offset_ = offset; } + + void set_picture(SkPicture* picture) { picture_ = skia::SharePtr(picture); } + + SkPicture* picture() const { return picture_.get(); } + + void Preroll(PrerollContext* frame, const SkMatrix& matrix) override; + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + SkPoint offset_; + skia::RefPtr picture_; + + // If we rasterized the picture separately, image_ holds the pixels. + skia::RefPtr image_; + + DISALLOW_COPY_AND_ASSIGN(PictureLayer); +}; + +} // namespace flow + +#endif // FLOW_PICTURE_LAYER_H_ diff --git a/engine/src/flutter/flow/raster_cache.cc b/engine/src/flutter/flow/raster_cache.cc new file mode 100644 index 00000000000..6ced53d6afc --- /dev/null +++ b/engine/src/flutter/flow/raster_cache.cc @@ -0,0 +1,114 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/raster_cache.h" + +#include "base/logging.h" +#include "base/trace_event/trace_event.h" +#include "flow/paint_context.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkSurface.h" + +#define ENABLE_RASTER_CACHE 1 + +namespace flow { + +#if ENABLE_RASTER_CACHE + +static const int kRasterThreshold = 3; + +static bool isWorthRasterizing(SkPicture* picture) { + // TODO(abarth): We should find a better heuristic here that lets us avoid + // wasting memory on trivial layers that are easy to re-rasterize every frame. + return picture->approximateOpCount() > 10 || picture->hasText(); +} + +#endif + +RasterCache::RasterCache() { +} + +RasterCache::~RasterCache() { +} + +RasterCache::Entry::Entry() { + physical_size.setEmpty(); +} + +RasterCache::Entry::~Entry() { +} + +skia::RefPtr RasterCache::GetPrerolledImage(GrContext* context, + SkPicture* picture, + const SkMatrix& ctm) { +#if ENABLE_RASTER_CACHE + SkScalar scaleX = ctm.getScaleX(); + SkScalar scaleY = ctm.getScaleY(); + + SkRect rect = picture->cullRect(); + + SkISize physical_size = SkISize::Make(rect.width() * scaleX, + rect.height() * scaleY); + + if (physical_size.isEmpty()) + return nullptr; + + Entry& entry = cache_[picture->uniqueID()]; + + const bool size_matched = entry.physical_size == physical_size; + + entry.used_this_frame = true; + entry.physical_size = physical_size; + + if (!size_matched) { + entry.access_count = 1; + entry.image = nullptr; + return nullptr; + } + + entry.access_count++; + + if (entry.access_count >= kRasterThreshold) { + // Saturate at the threshhold. + entry.access_count = kRasterThreshold; + + if (!entry.image && isWorthRasterizing(picture)) { + TRACE_EVENT2("flutter", "Rasterize picture layer", + "width", physical_size.width(), + "height", physical_size.height()); + SkImageInfo info = SkImageInfo::MakeN32Premul(physical_size); + skia::RefPtr surface = skia::AdoptRef( + SkSurface::NewRenderTarget(context, SkSurface::kYes_Budgeted, info)); + if (surface) { + SkCanvas* canvas = surface->getCanvas(); + canvas->clear(SK_ColorTRANSPARENT); + SkMatrix matrix = SkMatrix::MakeScale(scaleX, scaleY); + canvas->drawPicture(picture, &matrix, nullptr); + entry.image = skia::AdoptRef(surface->newImageSnapshot()); + } + } + } + + return entry.image; +#else + return nullptr; +#endif +} + +void RasterCache::SweepAfterFrame() { + std::vector dead; + + for (auto it = cache_.begin(); it != cache_.end(); ++it) { + Entry& entry = it->second; + if (!entry.used_this_frame) + dead.push_back(it); + entry.used_this_frame = false; + } + + for (auto it : dead) + cache_.erase(it); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/raster_cache.h b/engine/src/flutter/flow/raster_cache.h new file mode 100644 index 00000000000..884794f9810 --- /dev/null +++ b/engine/src/flutter/flow/raster_cache.h @@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_RASTER_CACHE_H_ +#define FLOW_RASTER_CACHE_H_ + +#include +#include + +#include "base/macros.h" +#include "skia/ext/refptr.h" +#include "third_party/skia/include/core/SkSize.h" +#include "third_party/skia/include/core/SkImage.h" +#include "flow/instrumentation.h" + +namespace flow { + +class RasterCache { + public: + RasterCache(); + ~RasterCache(); + + skia::RefPtr GetPrerolledImage( + GrContext* context, SkPicture* picture, const SkMatrix& ctm); + void SweepAfterFrame(); + + private: + struct Entry { + Entry(); + ~Entry(); + + bool used_this_frame = false; + int access_count = 0; + SkISize physical_size; + skia::RefPtr image; + }; + + using Cache = std::unordered_map; + Cache cache_; + + DISALLOW_COPY_AND_ASSIGN(RasterCache); +}; + +} // namespace flow + +#endif // FLOW_RASTER_CACHE_H_ diff --git a/engine/src/flutter/flow/shader_mask_layer.cc b/engine/src/flutter/flow/shader_mask_layer.cc new file mode 100644 index 00000000000..70e99f092f1 --- /dev/null +++ b/engine/src/flutter/flow/shader_mask_layer.cc @@ -0,0 +1,33 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/shader_mask_layer.h" + +namespace flow { + +ShaderMaskLayer::ShaderMaskLayer() { +} + +ShaderMaskLayer::~ShaderMaskLayer() { +} + +void ShaderMaskLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + ContainerLayer::Preroll(context, matrix); + set_paint_bounds(context->child_paint_bounds); +} + +void ShaderMaskLayer::Paint(PaintContext::ScopedFrame& frame) { + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, false); + canvas.saveLayer(&paint_bounds(), nullptr); + PaintChildren(frame); + + SkPaint paint; + paint.setXfermodeMode(transfer_mode_); + paint.setShader(shader_.get()); + canvas.translate(mask_rect_.left(), mask_rect_.top()); + canvas.drawRect(SkRect::MakeWH(mask_rect_.width(), mask_rect_.height()), paint); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/shader_mask_layer.h b/engine/src/flutter/flow/shader_mask_layer.h new file mode 100644 index 00000000000..226b4d1dc21 --- /dev/null +++ b/engine/src/flutter/flow/shader_mask_layer.h @@ -0,0 +1,43 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_SHADER_MASK_LAYER_H_ +#define FLOW_SHADER_MASK_LAYER_H_ + +#include "flow/container_layer.h" + +#include "third_party/skia/include/core/SkShader.h" + +namespace flow { + +class ShaderMaskLayer : public ContainerLayer { + public: + ShaderMaskLayer(); + ~ShaderMaskLayer() override; + + void set_shader(SkShader* shader) { shader_ = skia::SharePtr(shader); } + + void set_mask_rect(const SkRect& mask_rect) { + mask_rect_ = mask_rect; + } + + void set_transfer_mode(SkXfermode::Mode transfer_mode) { + transfer_mode_ = transfer_mode; + } + + protected: + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + skia::RefPtr shader_; + SkRect mask_rect_; + SkXfermode::Mode transfer_mode_; + + DISALLOW_COPY_AND_ASSIGN(ShaderMaskLayer); +}; + +} // namespace flow + +#endif // FLOW_SHADER_MASK_LAYER_H_ diff --git a/engine/src/flutter/flow/transform_layer.cc b/engine/src/flutter/flow/transform_layer.cc new file mode 100644 index 00000000000..062568c75dd --- /dev/null +++ b/engine/src/flutter/flow/transform_layer.cc @@ -0,0 +1,29 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flow/transform_layer.h" + +namespace flow { + +TransformLayer::TransformLayer() { +} + +TransformLayer::~TransformLayer() { +} + +void TransformLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { + SkMatrix childMatrix; + childMatrix.setConcat(matrix, transform_); + PrerollChildren(context, childMatrix); + transform_.mapRect(&context->child_paint_bounds); +} + +void TransformLayer::Paint(PaintContext::ScopedFrame& frame) { + SkCanvas& canvas = frame.canvas(); + SkAutoCanvasRestore save(&canvas, true); + canvas.concat(transform_); + PaintChildren(frame); +} + +} // namespace flow diff --git a/engine/src/flutter/flow/transform_layer.h b/engine/src/flutter/flow/transform_layer.h new file mode 100644 index 00000000000..a3b939f5361 --- /dev/null +++ b/engine/src/flutter/flow/transform_layer.h @@ -0,0 +1,30 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLOW_TRANSFORM_LAYER_H_ +#define FLOW_TRANSFORM_LAYER_H_ + +#include "flow/container_layer.h" + +namespace flow { + +class TransformLayer : public ContainerLayer { + public: + TransformLayer(); + ~TransformLayer() override; + + void set_transform(const SkMatrix& transform) { transform_ = transform; } + + void Preroll(PrerollContext* context, const SkMatrix& matrix) override; + void Paint(PaintContext::ScopedFrame& frame) override; + + private: + SkMatrix transform_; + + DISALLOW_COPY_AND_ASSIGN(TransformLayer); +}; + +} // namespace flow + +#endif // FLOW_TRANSFORM_LAYER_H_