Skip to content

Instantly share code, notes, and snippets.

@chinmaygarde
Created September 28, 2018 01:46
Show Gist options
  • Select an option

  • Save chinmaygarde/482cc515e918c9017c431dc0a0097cce to your computer and use it in GitHub Desktop.

Select an option

Save chinmaygarde/482cc515e918c9017c431dc0a0097cce to your computer and use it in GitHub Desktop.
diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc
index 29f9c93b5..80eda152d 100644
--- a/flow/layers/layer_tree.cc
+++ b/flow/layers/layer_tree.cc
@@ -6,7 +6,9 @@
#include "flutter/flow/layers/layer.h"
#include "flutter/fml/trace_event.h"
+#include "third_party/skia/include/core/SkImageInfo.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
+#include "third_party/skia/include/core/SkSurface.h"
namespace flow {
@@ -74,16 +76,40 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame) const {
root_layer_->Paint(context);
}
-sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
- TRACE_EVENT0("flutter", "LayerTree::Flatten");
+sk_sp<SkImage> LayerTree::ToRasterImage(GrContext* context,
+ const SkISize& image_size) const {
+ TRACE_EVENT0("flutter", "LayerTree::ToRasterImage");
- SkPictureRecorder recorder;
- auto canvas = recorder.beginRecording(bounds);
+ // Step 1: Allocate the render target. If there is valid GrContext, it must
+ // not be a raster context as that will not have access to texture backed
+ // images referenced in the layer tree hierarchy.
+
+ auto image_info = SkImageInfo::MakeN32Premul(image_size);
+
+ sk_sp<SkSurface> surface;
+
+ if (context) {
+ surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, image_info);
+ }
+
+ if (!surface) {
+ // This should only happen on test contexts. In such cases, there aren't
+ // going to be texture backed images anyway.
+ surface = SkSurface::MakeRaster(image_info);
+ }
+
+ if (!surface) {
+ return nullptr;
+ }
+
+ auto canvas = surface->getCanvas();
if (!canvas) {
return nullptr;
}
+ // Step 2: Write into the render target.
+
Layer::PrerollContext preroll_context{
nullptr, // raster_cache (don't consult the cache)
nullptr, // gr_context (used for the raster cache)
@@ -94,6 +120,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
const Stopwatch unused_stopwatch;
TextureRegistry unused_texture_registry;
SkMatrix root_surface_transformation;
+
// No root surface transformation. So assume identity.
root_surface_transformation.reset();
@@ -115,7 +142,16 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
}
}
- return recorder.finishRecordingAsPicture();
+ // Step 3: Snapshot the render target and transfer the device snapshot to the
+ // host for a raster image.
+
+ auto snapshot = surface->makeImageSnapshot();
+
+ if (!snapshot) {
+ return nullptr;
+ }
+
+ return snapshot->makeRasterImage();
}
} // namespace flow
diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h
index bae883ca2..d5af8f85d 100644
--- a/flow/layers/layer_tree.h
+++ b/flow/layers/layer_tree.h
@@ -34,7 +34,8 @@ class LayerTree {
void Paint(CompositorContext::ScopedFrame& frame) const;
- sk_sp<SkPicture> Flatten(const SkRect& bounds);
+ sk_sp<SkImage> ToRasterImage(GrContext* context,
+ const SkISize& image_size) const;
Layer* root_layer() const { return root_layer_.get(); }
diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc
index 2863f5307..d05bceba1 100644
--- a/lib/ui/compositing/scene.cc
+++ b/lib/ui/compositing/scene.cc
@@ -7,8 +7,6 @@
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/trace_event.h"
#include "flutter/lib/ui/painting/image.h"
-#include "third_party/skia/include/core/SkImageInfo.h"
-#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/tonic/converter/dart_converter.h"
#include "third_party/tonic/dart_args.h"
#include "third_party/tonic/dart_binding_macros.h"
@@ -38,13 +36,16 @@ fml::RefPtr<Scene> Scene::create(std::unique_ptr<flow::Layer> rootLayer,
Scene::Scene(std::unique_ptr<flow::Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
- bool checkerboardOffscreenLayers)
- : m_layerTree(new flow::LayerTree()) {
- m_layerTree->set_root_layer(std::move(rootLayer));
- m_layerTree->set_rasterizer_tracing_threshold(rasterizerTracingThreshold);
- m_layerTree->set_checkerboard_raster_cache_images(
+ bool checkerboardOffscreenLayers) {
+ auto layer_tree = std::make_unique<flow::LayerTree>();
+
+ layer_tree->set_root_layer(std::move(rootLayer));
+ layer_tree->set_rasterizer_tracing_threshold(rasterizerTracingThreshold);
+ layer_tree->set_checkerboard_raster_cache_images(
checkerboardRasterCacheImages);
- m_layerTree->set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);
+ layer_tree->set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);
+
+ m_layerTree = std::move(layer_tree);
}
Scene::~Scene() {}
@@ -53,50 +54,9 @@ void Scene::dispose() {
ClearDartWrapper();
}
-static sk_sp<SkImage> CreateSceneSnapshot(GrContext* context,
- sk_sp<SkPicture> picture,
- const SkSize& size) {
- TRACE_EVENT0("flutter", "CreateSceneSnapshot");
- auto image_info =
- SkImageInfo::MakeN32Premul(SkISize::Make(size.width(), size.height()));
-
- sk_sp<SkSurface> surface;
-
- if (context) {
- surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, image_info);
- }
-
- if (!surface) {
- surface = SkSurface::MakeRaster(image_info);
- }
-
- if (!surface) {
- return nullptr;
- }
-
- auto canvas = surface->getCanvas();
-
- if (!canvas) {
- return nullptr;
- }
-
- if (picture) {
- canvas->drawPicture(picture.get());
- }
-
- auto snapshot = surface->makeImageSnapshot();
-
- if (!snapshot) {
- return nullptr;
- }
-
- return snapshot->makeRasterImage();
-}
-
Dart_Handle Scene::toImage(uint32_t width,
uint32_t height,
Dart_Handle raw_image_callback) {
- TRACE_EVENT0("flutter", "Scene::toImage");
if (Dart_IsNull(raw_image_callback) || !Dart_IsClosure(raw_image_callback)) {
return tonic::ToDart("Image callback was invalid");
}
@@ -109,40 +69,37 @@ Dart_Handle Scene::toImage(uint32_t width,
return tonic::ToDart("Image dimensions for scene were invalid.");
}
- auto dart_state = UIDartState::Current();
-
- auto image_callback = std::make_unique<tonic::DartPersistentValue>(
- dart_state, raw_image_callback);
+ auto layer_tree = accessLayerTree();
- // We can't create an image on this task runner because we don't have a
- // graphics context. Even if we did, it would be slow anyway. Also, this
- // thread owns the sole reference to the layer tree. So we flatten the layer
- // tree into a picture and use that as the thread transport mechanism.
-
- auto bounds_size = SkSize::Make(width, height);
- auto picture = m_layerTree->Flatten(SkRect::MakeSize(bounds_size));
- if (!picture) {
+ if (!layer_tree) {
// Already in Dart scope.
- return tonic::ToDart("Could not flatten scene into a layer tree.");
+ return tonic::ToDart("Could not access the layer tree.");
}
+ auto dart_state = UIDartState::Current();
+
+ auto image_callback = std::make_unique<tonic::DartPersistentValue>(
+ dart_state, raw_image_callback);
+ auto bounds_size = SkISize::Make(width, height);
auto resource_context = dart_state->GetResourceContext();
auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner();
auto unref_queue = dart_state->GetSkiaUnrefQueue();
- // The picture has been prepared on the UI thread.
+ // This call is made on the UI thread. We need to hop to the IO thread (which
+ // has a GrContext) to snapshot the image before hopping back to the UI thread
+ // to complete the callback.
dart_state->GetTaskRunners().GetIOTaskRunner()->PostTask(
- fml::MakeCopyable([picture = std::move(picture), //
+ fml::MakeCopyable([layer_tree = std::move(layer_tree), //
bounds_size, //
resource_context = std::move(resource_context), //
ui_task_runner = std::move(ui_task_runner), //
image_callback = std::move(image_callback), //
unref_queue = std::move(unref_queue) //
]() mutable {
- // Snapshot the picture on the IO thread that contains an optional
+ // Rasterizer the layer tree on the IO thread that contains an optional
// GrContext.
- auto image = CreateSceneSnapshot(resource_context.get(),
- std::move(picture), bounds_size);
+ auto image =
+ layer_tree->ToRasterImage(resource_context.get(), bounds_size);
// Send the image back to the UI thread for submission back to the
// framework.
@@ -175,8 +132,8 @@ Dart_Handle Scene::toImage(uint32_t width,
return Dart_Null();
}
-std::unique_ptr<flow::LayerTree> Scene::takeLayerTree() {
- return std::move(m_layerTree);
+std::shared_ptr<flow::LayerTree> Scene::accessLayerTree() const {
+ return m_layerTree;
}
} // namespace blink
diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h
index 09f6a3e0d..a166f5526 100644
--- a/lib/ui/compositing/scene.h
+++ b/lib/ui/compositing/scene.h
@@ -29,7 +29,7 @@ class Scene : public RefCountedDartWrappable<Scene> {
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers);
- std::unique_ptr<flow::LayerTree> takeLayerTree();
+ std::shared_ptr<flow::LayerTree> accessLayerTree() const;
Dart_Handle toImage(uint32_t width,
uint32_t height,
@@ -45,7 +45,7 @@ class Scene : public RefCountedDartWrappable<Scene> {
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers);
- std::unique_ptr<flow::LayerTree> m_layerTree;
+ std::shared_ptr<flow::LayerTree> m_layerTree;
};
} // namespace blink
diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc
index d3509ed08..f66bc3774 100644
--- a/runtime/runtime_controller.cc
+++ b/runtime/runtime_controller.cc
@@ -252,7 +252,7 @@ void RuntimeController::ScheduleFrame() {
}
void RuntimeController::Render(Scene* scene) {
- client_.Render(scene->takeLayerTree());
+ client_.Render(scene->accessLayerTree());
}
void RuntimeController::UpdateSemantics(SemanticsUpdate* update) {
diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h
index 2a9bded0a..a13f09844 100644
--- a/runtime/runtime_delegate.h
+++ b/runtime/runtime_delegate.h
@@ -23,7 +23,7 @@ class RuntimeDelegate {
virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0;
- virtual void Render(std::unique_ptr<flow::LayerTree> layer_tree) = 0;
+ virtual void Render(std::shared_ptr<flow::LayerTree> layer_tree) = 0;
virtual void UpdateSemantics(
blink::SemanticsNodeUpdates update,
diff --git a/shell/common/animator.cc b/shell/common/animator.cc
index 727d521b7..f3c7b7ba5 100644
--- a/shell/common/animator.cc
+++ b/shell/common/animator.cc
@@ -132,7 +132,7 @@ void Animator::BeginFrame(fml::TimePoint frame_start_time,
}
}
-void Animator::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
+void Animator::Render(std::shared_ptr<flow::LayerTree> layer_tree) {
if (dimension_change_pending_ &&
layer_tree->frame_size() != last_layer_tree_size_) {
dimension_change_pending_ = false;
@@ -146,7 +146,7 @@ void Animator::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
}
// Commit the pending continuation.
- producer_continuation_.Complete(std::move(layer_tree));
+ producer_continuation_.Complete(layer_tree);
delegate_.OnAnimatorDraw(layer_tree_pipeline_);
}
diff --git a/shell/common/animator.h b/shell/common/animator.h
index 470f04b54..ab11ac5aa 100644
--- a/shell/common/animator.h
+++ b/shell/common/animator.h
@@ -38,7 +38,7 @@ class Animator final {
void RequestFrame(bool regenerate_layer_tree = true);
- void Render(std::unique_ptr<flow::LayerTree> layer_tree);
+ void Render(std::shared_ptr<flow::LayerTree> layer_tree);
void Start();
diff --git a/shell/common/engine.cc b/shell/common/engine.cc
index 2a9ee3f2c..254495624 100644
--- a/shell/common/engine.cc
+++ b/shell/common/engine.cc
@@ -379,7 +379,7 @@ void Engine::ScheduleFrame(bool regenerate_layer_tree) {
animator_->RequestFrame(regenerate_layer_tree);
}
-void Engine::Render(std::unique_ptr<flow::LayerTree> layer_tree) {
+void Engine::Render(std::shared_ptr<flow::LayerTree> layer_tree) {
if (!layer_tree)
return;
diff --git a/shell/common/engine.h b/shell/common/engine.h
index 06436ce36..f55a1c31e 100644
--- a/shell/common/engine.h
+++ b/shell/common/engine.h
@@ -129,7 +129,7 @@ class Engine final : public blink::RuntimeDelegate {
std::string DefaultRouteName() override;
// |blink::RuntimeDelegate|
- void Render(std::unique_ptr<flow::LayerTree> layer_tree) override;
+ void Render(std::shared_ptr<flow::LayerTree> layer_tree) override;
// |blink::RuntimeDelegate|
void UpdateSemantics(
diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc
index 6f08b2afd..21a1b1547 100644
--- a/shell/common/rasterizer.cc
+++ b/shell/common/rasterizer.cc
@@ -89,7 +89,7 @@ void Rasterizer::Draw(
}
}
-void Rasterizer::DoDraw(std::unique_ptr<flow::LayerTree> layer_tree) {
+void Rasterizer::DoDraw(std::shared_ptr<flow::LayerTree> layer_tree) {
if (!layer_tree || !surface_) {
return;
}
diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h
index 1d3c03d89..08d8a108c 100644
--- a/shell/common/rasterizer.h
+++ b/shell/common/rasterizer.h
@@ -71,11 +71,11 @@ class Rasterizer final {
blink::TaskRunners task_runners_;
std::unique_ptr<Surface> surface_;
std::unique_ptr<flow::CompositorContext> compositor_context_;
- std::unique_ptr<flow::LayerTree> last_layer_tree_;
+ std::shared_ptr<flow::LayerTree> last_layer_tree_;
fml::closure next_frame_callback_;
fml::WeakPtrFactory<Rasterizer> weak_factory_;
- void DoDraw(std::unique_ptr<flow::LayerTree> layer_tree);
+ void DoDraw(std::shared_ptr<flow::LayerTree> layer_tree);
bool DrawToSurface(flow::LayerTree& layer_tree);
diff --git a/synchronization/pipeline.h b/synchronization/pipeline.h
index 726adf64d..d8f4dfa1e 100644
--- a/synchronization/pipeline.h
+++ b/synchronization/pipeline.h
@@ -29,7 +29,7 @@ template <class R>
class Pipeline : public fml::RefCountedThreadSafe<Pipeline<R>> {
public:
using Resource = R;
- using ResourcePtr = std::unique_ptr<Resource>;
+ using ResourcePtr = std::shared_ptr<Resource>;
/// Denotes a spot in the pipeline reserved for the producer to finish
/// preparing a completed pipeline resource.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment