未验证 提交 387ca2ef 编写于 作者: A Amir Hardon 提交者: GitHub

Add an internal_nodes_canvas to PaintContext. (#6728)

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.
上级 22fc0202
......@@ -16,7 +16,6 @@ class EmbeddedViewParams {
public:
SkPoint offsetPixels;
SkSize sizePoints;
SkISize canvasBaseLayerSize;
};
// This is only used on iOS when running in a non headless mode,
......@@ -26,6 +25,12 @@ class ExternalViewEmbedder {
public:
ExternalViewEmbedder() = default;
virtual void SetFrameSize(SkISize frame_size) = 0;
virtual void PrerollCompositeEmbeddedView(int view_id) = 0;
virtual std::vector<SkCanvas*> GetCurrentCanvases() = 0;
// Must be called on the UI thread.
virtual SkCanvas* CompositeEmbeddedView(int view_id,
const EmbeddedViewParams& params) = 0;
......
......@@ -25,6 +25,7 @@
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRect.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h"
#if defined(OS_FUCHSIA)
......@@ -44,6 +45,7 @@ class ContainerLayer;
struct PrerollContext {
RasterCache* raster_cache;
GrContext* gr_context;
ExternalViewEmbedder* view_embedder;
SkColorSpace* dst_color_space;
SkRect child_paint_bounds;
......@@ -64,6 +66,21 @@ class Layer {
virtual void Preroll(PrerollContext* context, const SkMatrix& matrix);
struct PaintContext {
// When splitting the scene into multiple canvases (e.g when embedding
// a platform view on iOS) during the paint traversal we apply the non leaf
// flow layers to all canvases, and leaf layers just to the "current"
// canvas. Applying the non leaf layers to all canvases ensures that when
// we switch a canvas (when painting a PlatformViewLayer) the next canvas
// has the exact same state as the current canvas.
// The internal_nodes_canvas is a SkNWayCanvas which is used by non leaf
// and applies the operations to all canvases.
// The leaf_nodes_canvas is the "current" canvas and is used by leaf
// layers.
SkCanvas* internal_nodes_canvas;
// I'm temporarily leaving the name of this field to be canvas to reduce
// noise in the incremental change. A followup change will rename this
// and use the corrrect canvas in each callsite.
// TODO(amirh) rename canvas to leaf_nodes_canvas.
SkCanvas* canvas;
ExternalViewEmbedder* view_embedder;
const Stopwatch& frame_time;
......
......@@ -7,6 +7,7 @@
#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 {
......@@ -28,6 +29,7 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame,
PrerollContext context = {
ignore_raster_cache ? nullptr : &frame.context().raster_cache(),
frame.gr_context(),
frame.view_embedder(),
color_space,
SkRect::MakeEmpty(),
frame.context().frame_time(),
......@@ -66,7 +68,18 @@ void LayerTree::UpdateScene(SceneUpdateContext& context,
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(),
......@@ -98,6 +111,7 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
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)
......@@ -106,7 +120,12 @@ sk_sp<SkPicture> LayerTree::Flatten(const SkRect& bounds) {
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)
......
......@@ -14,6 +14,13 @@ void PlatformViewLayer::Preroll(PrerollContext* context,
const SkMatrix& matrix) {
set_paint_bounds(SkRect::MakeXYWH(offset_.x(), offset_.y(), size_.width(),
size_.height()));
if (context->view_embedder == nullptr) {
FML_LOG(ERROR) << "Trying to embed a platform view but the PrerollContext "
"does not support embedding";
return;
}
context->view_embedder->PrerollCompositeEmbeddedView(view_id_);
}
void PlatformViewLayer::Paint(PaintContext& context) const {
......@@ -27,12 +34,9 @@ void PlatformViewLayer::Paint(PaintContext& context) const {
params.offsetPixels =
SkPoint::Make(transform.getTranslateX(), transform.getTranslateY());
params.sizePoints = size_;
params.canvasBaseLayerSize = context.canvas->getBaseLayerSize();
SkCanvas* canvas =
context.view_embedder->CompositeEmbeddedView(view_id_, params);
// TODO(amirh): copy the full canvas state here
canvas->concat(context.canvas->getTotalMatrix());
context.canvas = canvas;
}
} // namespace flow
......@@ -36,8 +36,8 @@ void TransformLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "TransformLayer::Paint");
FML_DCHECK(needs_painting());
SkAutoCanvasRestore save(context.canvas, true);
context.canvas->concat(transform_);
SkAutoCanvasRestore save(context.internal_nodes_canvas, true);
context.internal_nodes_canvas->concat(transform_);
PaintChildren(context);
}
......
......@@ -156,7 +156,12 @@ void RasterCache::Prepare(PrerollContext* context,
entry.image = Rasterize(context->gr_context, ctm, context->dst_color_space,
checkerboard_images_, layer->paint_bounds(),
[layer, context](SkCanvas* canvas) {
SkISize canvas_size = canvas->getBaseLayerSize();
SkNWayCanvas internal_nodes_canvas(
canvas_size.width(), canvas_size.height());
internal_nodes_canvas.addCanvas(canvas);
Layer::PaintContext paintContext = {
(SkCanvas*)&internal_nodes_canvas,
canvas,
nullptr,
context->frame_time,
......
......@@ -188,6 +188,7 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
FML_DCHECK(task.surface);
SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
Layer::PaintContext context = {canvas,
canvas,
nullptr,
frame.context().frame_time(),
frame.context().engine_time(),
......
......@@ -164,6 +164,11 @@ bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) {
auto external_view_embedder = surface_->GetExternalViewEmbedder();
// TODO(amirh): uncomment this once external_view_embedder is populated.
// if (external_view_embedder != nullptr) {
// external_view_embedder->SetFrameSize(layer_tree.frame_size());
// }
auto compositor_frame = compositor_context_->AcquireFrame(
surface_->GetContext(), canvas, external_view_embedder,
surface_->GetRootTransformation(), true);
......
......@@ -128,6 +128,25 @@ void FlutterPlatformViewsController::RegisterViewFactory(
fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>([factory retain]);
}
void FlutterPlatformViewsController::SetFrameSize(SkISize frame_size) {
frame_size_ = frame_size;
}
void FlutterPlatformViewsController::PrerollCompositeEmbeddedView(int view_id) {
EnsureOverlayInitialized(view_id);
composition_frames_[view_id] = (overlays_[view_id]->surface->AcquireFrame(frame_size_));
composition_order_.push_back(view_id);
}
std::vector<SkCanvas*> FlutterPlatformViewsController::GetCurrentCanvases() {
std::vector<SkCanvas*> canvases;
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t view_id = composition_order_[i];
canvases.push_back(composition_frames_[view_id]->SkiaCanvas());
}
return canvases;
}
SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
int view_id,
const flow::EmbeddedViewParams& params,
......@@ -135,7 +154,6 @@ SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
// TODO(amirh): assert that this is running on the platform thread once we support the iOS
// embedded views thread configuration.
// TODO(amirh): do nothing if the params didn't change.
EnsureOverlayInitialized(view_id);
CGFloat screenScale = [[UIScreen mainScreen] scale];
CGRect rect =
CGRectMake(params.offsetPixels.x() / screenScale, params.offsetPixels.y() / screenScale,
......@@ -143,19 +161,17 @@ SkCanvas* FlutterPlatformViewsController::CompositeEmbeddedView(
UIView* view = views_[view_id].get();
[view setFrame:rect];
composition_order_.push_back(view_id);
composition_frames_.push_back(
overlays_[view_id]->surface->AcquireFrame(params.canvasBaseLayerSize));
SkCanvas* canvas = composition_frames_.back()->SkiaCanvas();
SkCanvas* canvas = composition_frames_[view_id]->SkiaCanvas();
canvas->clear(SK_ColorTRANSPARENT);
return canvas;
}
bool FlutterPlatformViewsController::Present() {
bool did_submit = true;
for (size_t i = 0; i < composition_frames_.size(); i++) {
did_submit &= composition_frames_[i]->Submit();
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t view_id = composition_order_[i];
did_submit &= composition_frames_[view_id]->Submit();
}
composition_frames_.clear();
if (composition_order_ == active_composition_order_) {
......
......@@ -49,6 +49,12 @@ class FlutterPlatformViewsController {
void RegisterViewFactory(NSObject<FlutterPlatformViewFactory>* factory, NSString* factoryId);
void SetFrameSize(SkISize frame_size);
void PrerollCompositeEmbeddedView(int view_id);
std::vector<SkCanvas*> GetCurrentCanvases();
SkCanvas* CompositeEmbeddedView(int view_id,
const flow::EmbeddedViewParams& params,
IOSSurface& surface);
......@@ -63,6 +69,7 @@ class FlutterPlatformViewsController {
std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> factories_;
std::map<int64_t, fml::scoped_nsobject<FlutterTouchInterceptingView>> views_;
std::map<int64_t, std::unique_ptr<FlutterPlatformViewLayer>> overlays_;
SkISize frame_size_;
// A vector of embedded view IDs according to their composition order.
// The last ID in this vector belond to the that is composited on top of all others.
......@@ -71,7 +78,7 @@ class FlutterPlatformViewsController {
// The latest composition order that was presented in Present().
std::vector<int64_t> active_composition_order_;
std::vector<std::unique_ptr<SurfaceFrame>> composition_frames_;
std::map<int64_t, std::unique_ptr<SurfaceFrame>> composition_frames_;
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
void OnDispose(FlutterMethodCall* call, FlutterResult& result);
......
......@@ -45,6 +45,15 @@ class IOSSurfaceGL : public IOSSurface,
// |shell::GPUSurfaceGLDelegate|
flow::ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |flow::ExternalViewEmbedder|
void SetFrameSize(SkISize frame_size) override;
// |flow::ExternalViewEmbedder|
void PrerollCompositeEmbeddedView(int view_id) override;
// |flow::ExternalViewEmbedder|
std::vector<SkCanvas*> GetCurrentCanvases() override;
// |flow::ExternalViewEmbedder|
SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override;
......
......@@ -74,6 +74,24 @@ flow::ExternalViewEmbedder* IOSSurfaceGL::GetExternalViewEmbedder() {
}
}
void IOSSurfaceGL::SetFrameSize(SkISize frame_size) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->SetFrameSize(frame_size);
}
void IOSSurfaceGL::PrerollCompositeEmbeddedView(int view_id) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->PrerollCompositeEmbeddedView(view_id);
}
std::vector<SkCanvas*> IOSSurfaceGL::GetCurrentCanvases() {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->GetCurrentCanvases();
}
SkCanvas* IOSSurfaceGL::CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
......
......@@ -45,6 +45,15 @@ class IOSSurfaceSoftware final : public IOSSurface,
// |shell::GPUSurfaceSoftwareDelegate|
flow::ExternalViewEmbedder* GetExternalViewEmbedder() override;
// |flow::ExternalViewEmbedder|
void SetFrameSize(SkISize frame_size) override;
// |flow::ExternalViewEmbedder|
void PrerollCompositeEmbeddedView(int view_id) override;
// |flow::ExternalViewEmbedder|
std::vector<SkCanvas*> GetCurrentCanvases() override;
// |flow::ExternalViewEmbedder|
SkCanvas* CompositeEmbeddedView(int view_id, const flow::EmbeddedViewParams& params) override;
......
......@@ -138,6 +138,24 @@ flow::ExternalViewEmbedder* IOSSurfaceSoftware::GetExternalViewEmbedder() {
}
}
void IOSSurfaceSoftware::SetFrameSize(SkISize frame_size) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->SetFrameSize(frame_size);
}
void IOSSurfaceSoftware::PrerollCompositeEmbeddedView(int view_id) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
platform_views_controller->PrerollCompositeEmbeddedView(view_id);
}
std::vector<SkCanvas*> IOSSurfaceSoftware::GetCurrentCanvases() {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
FML_CHECK(platform_views_controller != nullptr);
return platform_views_controller->GetCurrentCanvases();
}
SkCanvas* IOSSurfaceSoftware::CompositeEmbeddedView(int view_id,
const flow::EmbeddedViewParams& params) {
FlutterPlatformViewsController* platform_views_controller = GetPlatformViewsController();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册