Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions flow/layers/layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@

namespace flutter {

LayerTree::LayerTree(const SkISize& frame_size, float device_pixel_ratio)
: frame_size_(frame_size),
LayerTree::LayerTree(const Config& config,
const SkISize& frame_size,
float device_pixel_ratio)
: root_layer_(config.root_layer),
frame_size_(frame_size),
device_pixel_ratio_(device_pixel_ratio),
rasterizer_tracing_threshold_(0),
checkerboard_raster_cache_images_(false),
checkerboard_offscreen_layers_(false) {
rasterizer_tracing_threshold_(config.rasterizer_tracing_threshold),
checkerboard_raster_cache_images_(
config.checkerboard_raster_cache_images),
checkerboard_offscreen_layers_(config.checkerboard_offscreen_layers) {
FML_CHECK(device_pixel_ratio_ != 0.0f);
}

Expand Down
32 changes: 12 additions & 20 deletions flow/layers/layer_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ namespace flutter {

class LayerTree {
public:
LayerTree(const SkISize& frame_size, float device_pixel_ratio);
struct Config {
std::shared_ptr<Layer> root_layer;
uint32_t rasterizer_tracing_threshold = 0;
bool checkerboard_raster_cache_images = false;
bool checkerboard_offscreen_layers = false;
};

LayerTree(const Config& config,
const SkISize& frame_size,
float device_pixel_ratio);

// Perform a preroll pass on the tree and return information about
// the tree that affects rendering this frame.
Expand All @@ -50,36 +59,19 @@ class LayerTree {
GrDirectContext* gr_context = nullptr);

Layer* root_layer() const { return root_layer_.get(); }

void set_root_layer(std::shared_ptr<Layer> root_layer) {
root_layer_ = std::move(root_layer);
}

const SkISize& frame_size() const { return frame_size_; }
float device_pixel_ratio() const { return device_pixel_ratio_; }

const PaintRegionMap& paint_region_map() const { return paint_region_map_; }
PaintRegionMap& paint_region_map() { return paint_region_map_; }

// 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_threshold_ = interval;
}

// trace the rasterized picture to a trace file. 0 stands for disabling all
// tracing.
uint32_t rasterizer_tracing_threshold() const {
return rasterizer_tracing_threshold_;
}

void set_checkerboard_raster_cache_images(bool checkerboard) {
checkerboard_raster_cache_images_ = checkerboard;
}

void set_checkerboard_offscreen_layers(bool checkerboard) {
checkerboard_offscreen_layers_ = checkerboard;
}

/// When `Paint` is called, if leaf layer tracing is enabled, additional
/// metadata around raterization of leaf layers is collected.
///
Expand Down
55 changes: 34 additions & 21 deletions flow/layers/layer_tree_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ namespace testing {
class LayerTreeTest : public CanvasTest {
public:
LayerTreeTest()
: layer_tree_(SkISize::Make(64, 64), 1.0f),
root_transform_(SkMatrix::Translate(1.0f, 1.0f)),
: root_transform_(SkMatrix::Translate(1.0f, 1.0f)),
scoped_frame_(compositor_context_.AcquireFrame(nullptr,
&mock_canvas(),
nullptr,
Expand All @@ -31,12 +30,14 @@ class LayerTreeTest : public CanvasTest {
nullptr,
nullptr)) {}

LayerTree& layer_tree() { return layer_tree_; }
CompositorContext::ScopedFrame& frame() { return *scoped_frame_.get(); }
const SkMatrix& root_transform() { return root_transform_; }

std::unique_ptr<LayerTree> BuildLayerTree(const LayerTree::Config& config) {
return std::make_unique<LayerTree>(config, SkISize::Make(64, 64), 1.0f);
}

private:
LayerTree layer_tree_;
CompositorContext compositor_context_;
SkMatrix root_transform_;
std::unique_ptr<CompositorContext::ScopedFrame> scoped_frame_;
Expand All @@ -45,12 +46,14 @@ class LayerTreeTest : public CanvasTest {
TEST_F(LayerTreeTest, PaintingEmptyLayerDies) {
auto layer = std::make_shared<ContainerLayer>();

layer_tree().set_root_layer(layer);
layer_tree().Preroll(frame());
auto layer_tree = BuildLayerTree(LayerTree::Config{
.root_layer = layer,
});
layer_tree->Preroll(frame());
EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
EXPECT_TRUE(layer->is_empty());

layer_tree().Paint(frame());
layer_tree->Paint(frame());
}

TEST_F(LayerTreeTest, PaintBeforePrerollDies) {
Expand All @@ -61,13 +64,15 @@ TEST_F(LayerTreeTest, PaintBeforePrerollDies) {
auto layer = std::make_shared<ContainerLayer>();
layer->Add(mock_layer);

layer_tree().set_root_layer(layer);
auto layer_tree = BuildLayerTree(LayerTree::Config{
.root_layer = layer,
});
EXPECT_EQ(mock_layer->paint_bounds(), kEmptyRect);
EXPECT_EQ(layer->paint_bounds(), kEmptyRect);
EXPECT_TRUE(mock_layer->is_empty());
EXPECT_TRUE(layer->is_empty());

layer_tree().Paint(frame());
layer_tree->Paint(frame());
EXPECT_EQ(mock_canvas().draw_calls(), std::vector<MockCanvas::DrawCall>());
}

Expand All @@ -79,15 +84,17 @@ TEST_F(LayerTreeTest, Simple) {
auto layer = std::make_shared<ContainerLayer>();
layer->Add(mock_layer);

layer_tree().set_root_layer(layer);
layer_tree().Preroll(frame());
auto layer_tree = BuildLayerTree(LayerTree::Config{
.root_layer = layer,
});
layer_tree->Preroll(frame());
EXPECT_EQ(mock_layer->paint_bounds(), child_bounds);
EXPECT_EQ(layer->paint_bounds(), mock_layer->paint_bounds());
EXPECT_FALSE(mock_layer->is_empty());
EXPECT_FALSE(layer->is_empty());
EXPECT_EQ(mock_layer->parent_matrix(), root_transform());

layer_tree().Paint(frame());
layer_tree->Paint(frame());
EXPECT_EQ(mock_canvas().draw_calls(),
std::vector({MockCanvas::DrawCall{
0, MockCanvas::DrawPathData{child_path, child_paint}}}));
Expand All @@ -107,8 +114,10 @@ TEST_F(LayerTreeTest, Multiple) {

SkRect expected_total_bounds = child_path1.getBounds();
expected_total_bounds.join(child_path2.getBounds());
layer_tree().set_root_layer(layer);
layer_tree().Preroll(frame());
auto layer_tree = BuildLayerTree(LayerTree::Config{
.root_layer = layer,
});
layer_tree->Preroll(frame());
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
EXPECT_EQ(layer->paint_bounds(), expected_total_bounds);
Expand All @@ -121,7 +130,7 @@ TEST_F(LayerTreeTest, Multiple) {
EXPECT_EQ(mock_layer2->parent_cull_rect(),
kGiantRect); // Siblings are independent

layer_tree().Paint(frame());
layer_tree->Paint(frame());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector({MockCanvas::DrawCall{
Expand All @@ -140,8 +149,10 @@ TEST_F(LayerTreeTest, MultipleWithEmpty) {
layer->Add(mock_layer1);
layer->Add(mock_layer2);

layer_tree().set_root_layer(layer);
layer_tree().Preroll(frame());
auto layer_tree = BuildLayerTree(LayerTree::Config{
.root_layer = layer,
});
layer_tree->Preroll(frame());
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
EXPECT_EQ(mock_layer2->paint_bounds(), SkPath().getBounds());
EXPECT_EQ(layer->paint_bounds(), child_path1.getBounds());
Expand All @@ -153,7 +164,7 @@ TEST_F(LayerTreeTest, MultipleWithEmpty) {
EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect);
EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect);

layer_tree().Paint(frame());
layer_tree->Paint(frame());
EXPECT_EQ(mock_canvas().draw_calls(),
std::vector({MockCanvas::DrawCall{
0, MockCanvas::DrawPathData{child_path1, child_paint1}}}));
Expand All @@ -172,8 +183,10 @@ TEST_F(LayerTreeTest, NeedsSystemComposite) {

SkRect expected_total_bounds = child_path1.getBounds();
expected_total_bounds.join(child_path2.getBounds());
layer_tree().set_root_layer(layer);
layer_tree().Preroll(frame());
auto layer_tree = BuildLayerTree(LayerTree::Config{
.root_layer = layer,
});
layer_tree->Preroll(frame());
EXPECT_EQ(mock_layer1->paint_bounds(), child_path1.getBounds());
EXPECT_EQ(mock_layer2->paint_bounds(), child_path2.getBounds());
EXPECT_EQ(layer->paint_bounds(), expected_total_bounds);
Expand All @@ -185,7 +198,7 @@ TEST_F(LayerTreeTest, NeedsSystemComposite) {
EXPECT_EQ(mock_layer1->parent_cull_rect(), kGiantRect);
EXPECT_EQ(mock_layer2->parent_cull_rect(), kGiantRect);

layer_tree().Paint(frame());
layer_tree->Paint(frame());
EXPECT_EQ(
mock_canvas().draw_calls(),
std::vector({MockCanvas::DrawCall{
Expand Down
92 changes: 56 additions & 36 deletions lib/ui/compositing/scene.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

namespace flutter {

static constexpr float kFallbackPixelRatio = 2.0f;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably have a comment answering questions like: Why is this 2.0? When do we fallback to this? Is this just meant to support legacy behavior and new logic should not use this constant? Or when should new logic use this constant?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I see that this is kinda explained on defaultViewPixelRatio, might be worthwhile to link to that here)


IMPLEMENT_WRAPPERTYPEINFO(ui, Scene);

void Scene::create(Dart_Handle scene_handle,
Expand All @@ -40,27 +42,22 @@ Scene::Scene(std::shared_ptr<flutter::Layer> rootLayer,
uint32_t rasterizerTracingThreshold,
bool checkerboardRasterCacheImages,
bool checkerboardOffscreenLayers) {
// Currently only supports a single window.
auto viewport_metrics = UIDartState::Current()
->platform_configuration()
->get_window(0)
->viewport_metrics();

layer_tree_ = std::make_shared<LayerTree>(
SkISize::Make(viewport_metrics.physical_width,
viewport_metrics.physical_height),
static_cast<float>(viewport_metrics.device_pixel_ratio));
layer_tree_->set_root_layer(std::move(rootLayer));
layer_tree_->set_rasterizer_tracing_threshold(rasterizerTracingThreshold);
layer_tree_->set_checkerboard_raster_cache_images(
checkerboardRasterCacheImages);
layer_tree_->set_checkerboard_offscreen_layers(checkerboardOffscreenLayers);
layer_tree_config_.root_layer = std::move(rootLayer);
layer_tree_config_.rasterizer_tracing_threshold = rasterizerTracingThreshold;
layer_tree_config_.checkerboard_raster_cache_images =
checkerboardRasterCacheImages;
layer_tree_config_.checkerboard_offscreen_layers =
checkerboardOffscreenLayers;
}

Scene::~Scene() {}

bool Scene::valid() {
return layer_tree_config_.root_layer != nullptr;
}

void Scene::dispose() {
layer_tree_.reset();
layer_tree_config_.root_layer.reset();
ClearDartWrapper();
}

Expand All @@ -69,11 +66,12 @@ Dart_Handle Scene::toImageSync(uint32_t width,
Dart_Handle raw_image_handle) {
TRACE_EVENT0("flutter", "Scene::toImageSync");

if (!layer_tree_) {
return tonic::ToDart("Scene did not contain a layer tree.");
if (!valid()) {
return tonic::ToDart("Scene has been disposed.");
}

Scene::RasterizeToImage(width, height, raw_image_handle);
Scene::RasterizeToImage(width, height, defaultViewPixelRatio(),
raw_image_handle);
return Dart_Null();
}

Expand All @@ -82,39 +80,41 @@ Dart_Handle Scene::toImage(uint32_t width,
Dart_Handle raw_image_callback) {
TRACE_EVENT0("flutter", "Scene::toImage");

if (!layer_tree_) {
return tonic::ToDart("Scene did not contain a layer tree.");
if (!valid()) {
return tonic::ToDart("Scene has been disposed.");
}

return Picture::RasterizeLayerTreeToImage(std::move(layer_tree_), width,
height, raw_image_callback);
return Picture::RasterizeLayerTreeToImage(
BuildLayerTree(width, height, defaultViewPixelRatio()),
raw_image_callback);
}

static sk_sp<DlImage> CreateDeferredImage(
bool impeller,
std::shared_ptr<LayerTree> layer_tree,
uint32_t width,
uint32_t height,
std::unique_ptr<LayerTree> layer_tree,
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
fml::RefPtr<fml::TaskRunner> raster_task_runner,
fml::RefPtr<SkiaUnrefQueue> unref_queue) {
#if IMPELLER_SUPPORTS_RENDERING
if (impeller) {
return DlDeferredImageGPUImpeller::Make(
std::move(layer_tree), SkISize::Make(width, height),
std::move(snapshot_delegate), std::move(raster_task_runner));
return DlDeferredImageGPUImpeller::Make(std::move(layer_tree),
std::move(snapshot_delegate),
std::move(raster_task_runner));
}
#endif // IMPELLER_SUPPORTS_RENDERING

const SkImageInfo image_info = SkImageInfo::Make(
width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
const auto& frame_size = layer_tree->frame_size();
const SkImageInfo image_info =
SkImageInfo::Make(frame_size.width(), frame_size.height(),
kRGBA_8888_SkColorType, kPremul_SkAlphaType);
return DlDeferredImageGPUSkia::MakeFromLayerTree(
image_info, std::move(layer_tree), std::move(snapshot_delegate),
raster_task_runner, std::move(unref_queue));
}

void Scene::RasterizeToImage(uint32_t width,
uint32_t height,
float pixel_ratio,
Dart_Handle raw_image_handle) {
auto* dart_state = UIDartState::Current();
if (!dart_state) {
Expand All @@ -126,15 +126,35 @@ void Scene::RasterizeToImage(uint32_t width,

auto image = CanvasImage::Create();
auto dl_image = CreateDeferredImage(
dart_state->IsImpellerEnabled(), layer_tree_, width, height,
std::move(snapshot_delegate), std::move(raster_task_runner),
std::move(unref_queue));
dart_state->IsImpellerEnabled(),
BuildLayerTree(width, height, pixel_ratio), std::move(snapshot_delegate),
std::move(raster_task_runner), std::move(unref_queue));
image->set_image(dl_image);
image->AssociateWithDartWrapper(raw_image_handle);
}

std::shared_ptr<flutter::LayerTree> Scene::takeLayerTree() {
return std::move(layer_tree_);
std::unique_ptr<flutter::LayerTree> Scene::takeLayerTree(uint64_t width,
uint64_t height,
float pixel_ratio) {
return BuildLayerTree(width, height, pixel_ratio);
}

std::unique_ptr<LayerTree> Scene::BuildLayerTree(uint32_t width,
uint32_t height,
float pixel_ratio) {
if (!valid()) {
return nullptr;
}
return std::make_unique<LayerTree>(layer_tree_config_,
SkISize::Make(width, height), pixel_ratio);
}

float Scene::defaultViewPixelRatio() {
auto window = UIDartState::Current()->platform_configuration()->get_window(0);
if (window != nullptr) {
return static_cast<float>(window->viewport_metrics().device_pixel_ratio);
}
return kFallbackPixelRatio;
}

} // namespace flutter
Loading