mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
When we visit a PlatformViewLayer during the paint traversal it replaces the PaintContext's canvas with a new one that is painted ontop of the embedded view. We need to make sure that operations applied by parent layers are also applied to the new canvas. To achieve this we collect all the canvases in a SkNWayCanvas and use this canvas by non leaf nodes. Leaf nodes still paint only to the "current" canvas. This PR moves the overlay canvas creation from the paint phase to the preroll phase, collects them into a SkNWayCanvas and set it in PaintContext. To keep this PR focused, I only used the internal_nodes_canvas in the tranform_layer. Will followup with a PR that changes all internal layers to use the internal_nodes_canvas.
152 lines
5.4 KiB
C++
152 lines
5.4 KiB
C++
// Copyright 2013 The Flutter 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 "flutter/flow/layers/layer_tree.h"
|
|
|
|
#include "flutter/flow/layers/layer.h"
|
|
#include "flutter/fml/trace_event.h"
|
|
#include "third_party/skia/include/core/SkPictureRecorder.h"
|
|
#include "third_party/skia/include/utils/SkNWayCanvas.h"
|
|
|
|
namespace flow {
|
|
|
|
LayerTree::LayerTree()
|
|
: frame_size_{},
|
|
rasterizer_tracing_threshold_(0),
|
|
checkerboard_raster_cache_images_(false),
|
|
checkerboard_offscreen_layers_(false) {}
|
|
|
|
LayerTree::~LayerTree() = default;
|
|
|
|
void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
|
|
bool ignore_raster_cache) {
|
|
TRACE_EVENT0("flutter", "LayerTree::Preroll");
|
|
SkColorSpace* color_space =
|
|
frame.canvas() ? frame.canvas()->imageInfo().colorSpace() : nullptr;
|
|
frame.context().raster_cache().SetCheckboardCacheImages(
|
|
checkerboard_raster_cache_images_);
|
|
PrerollContext context = {
|
|
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
|
|
frame.gr_context(),
|
|
frame.view_embedder(),
|
|
color_space,
|
|
SkRect::MakeEmpty(),
|
|
frame.context().frame_time(),
|
|
frame.context().engine_time(),
|
|
frame.context().texture_registry(),
|
|
checkerboard_offscreen_layers_};
|
|
|
|
root_layer_->Preroll(&context, frame.root_surface_transformation());
|
|
}
|
|
|
|
#if defined(OS_FUCHSIA)
|
|
void LayerTree::UpdateScene(SceneUpdateContext& context,
|
|
scenic::ContainerNode& container) {
|
|
TRACE_EVENT0("flutter", "LayerTree::UpdateScene");
|
|
const auto& metrics = context.metrics();
|
|
SceneUpdateContext::Transform transform(context, // context
|
|
1.0f / metrics->scale_x, // X
|
|
1.0f / metrics->scale_y, // Y
|
|
1.0f / metrics->scale_z // Z
|
|
);
|
|
SceneUpdateContext::Frame frame(
|
|
context,
|
|
SkRRect::MakeRect(
|
|
SkRect::MakeWH(frame_size_.width(), frame_size_.height())),
|
|
SK_ColorTRANSPARENT, 0.f);
|
|
if (root_layer_->needs_system_composite()) {
|
|
root_layer_->UpdateScene(context);
|
|
}
|
|
if (root_layer_->needs_painting()) {
|
|
frame.AddPaintedLayer(root_layer_.get());
|
|
}
|
|
container.AddChild(transform.entity_node());
|
|
}
|
|
#endif
|
|
|
|
void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
|
|
bool ignore_raster_cache) const {
|
|
TRACE_EVENT0("flutter", "LayerTree::Paint");
|
|
SkISize canvas_size = frame.canvas()->getBaseLayerSize();
|
|
SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height());
|
|
internal_nodes_canvas.addCanvas(frame.canvas());
|
|
if (frame.view_embedder() != nullptr) {
|
|
auto overlay_canvases = frame.view_embedder()->GetCurrentCanvases();
|
|
for (size_t i = 0; i < overlay_canvases.size(); i++) {
|
|
internal_nodes_canvas.addCanvas(overlay_canvases[i]);
|
|
}
|
|
}
|
|
|
|
Layer::PaintContext context = {
|
|
(SkCanvas*)&internal_nodes_canvas,
|
|
frame.canvas(),
|
|
frame.view_embedder(),
|
|
frame.context().frame_time(),
|
|
frame.context().engine_time(),
|
|
frame.context().texture_registry(),
|
|
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
|
|
checkerboard_offscreen_layers_};
|
|
|
|
if (root_layer_->needs_painting())
|
|
root_layer_->Paint(context);
|
|
}
|
|
|
|
sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
|
|
TRACE_EVENT0("flutter", "LayerTree::Flatten");
|
|
|
|
SkPictureRecorder recorder;
|
|
auto canvas = recorder.beginRecording(bounds);
|
|
|
|
if (!canvas) {
|
|
return nullptr;
|
|
}
|
|
|
|
const Stopwatch unused_stopwatch;
|
|
TextureRegistry unused_texture_registry;
|
|
SkMatrix root_surface_transformation;
|
|
// No root surface transformation. So assume identity.
|
|
root_surface_transformation.reset();
|
|
|
|
PrerollContext preroll_context{
|
|
nullptr, // raster_cache (don't consult the cache)
|
|
nullptr, // gr_context (used for the raster cache)
|
|
nullptr, // external view embedder
|
|
nullptr, // SkColorSpace* dst_color_space
|
|
SkRect::MakeEmpty(), // SkRect child_paint_bounds
|
|
unused_stopwatch, // frame time (dont care)
|
|
unused_stopwatch, // engine time (dont care)
|
|
unused_texture_registry, // texture registry (not supported)
|
|
false, // checkerboard_offscreen_layers
|
|
};
|
|
|
|
SkISize canvas_size = canvas->getBaseLayerSize();
|
|
SkNWayCanvas internal_nodes_canvas(canvas_size.width(), canvas_size.height());
|
|
internal_nodes_canvas.addCanvas(canvas);
|
|
|
|
Layer::PaintContext paint_context = {
|
|
(SkCanvas*)&internal_nodes_canvas,
|
|
canvas, // canvas
|
|
nullptr,
|
|
unused_stopwatch, // frame time (dont care)
|
|
unused_stopwatch, // engine time (dont care)
|
|
unused_texture_registry, // texture registry (not supported)
|
|
nullptr, // raster cache
|
|
false // checkerboard offscreen layers
|
|
};
|
|
|
|
// Even if we don't have a root layer, we still need to create an empty
|
|
// picture.
|
|
if (root_layer_) {
|
|
root_layer_->Preroll(&preroll_context, root_surface_transformation);
|
|
// The needs painting flag may be set after the preroll. So check it after.
|
|
if (root_layer_->needs_painting()) {
|
|
root_layer_->Paint(paint_context);
|
|
}
|
|
}
|
|
|
|
return recorder.finishRecordingAsPicture();
|
|
}
|
|
|
|
} // namespace flow
|