scene_update_context.cc 12.5 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4 5 6 7
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/scene_update_context.h"

#include "flutter/flow/layers/layer.h"
8
#include "flutter/flow/matrix_decomposition.h"
9
#include "flutter/fml/trace_event.h"
10

11
namespace flutter {
12

13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
// Helper function to generate clip planes for a scenic::EntityNode.
static void SetEntityNodeClipPlanes(scenic::EntityNode* entity_node,
                                    const SkRect& bounds) {
  const float top = bounds.top();
  const float bottom = bounds.bottom();
  const float left = bounds.left();
  const float right = bounds.right();

  // We will generate 4 oriented planes, one for each edge of the bounding rect.
  std::vector<fuchsia::ui::gfx::Plane3> clip_planes;
  clip_planes.resize(4);

  // Top plane.
  clip_planes[0].dist = top;
  clip_planes[0].dir.x = 0.f;
  clip_planes[0].dir.y = 1.f;
  clip_planes[0].dir.z = 0.f;

  // Bottom plane.
  clip_planes[1].dist = -bottom;
  clip_planes[1].dir.x = 0.f;
  clip_planes[1].dir.y = -1.f;
  clip_planes[1].dir.z = 0.f;

  // Left plane.
  clip_planes[2].dist = left;
  clip_planes[2].dir.x = 1.f;
  clip_planes[2].dir.y = 0.f;
  clip_planes[2].dir.z = 0.f;

  // Right plane.
  clip_planes[3].dist = -right;
  clip_planes[3].dir.x = -1.f;
  clip_planes[3].dir.y = 0.f;
  clip_planes[3].dir.z = 0.f;

  entity_node->SetClipPlanes(std::move(clip_planes));
}

52 53 54 55 56 57
SceneUpdateContext::SceneUpdateContext(scenic::Session* session,
                                       SurfaceProducer* surface_producer)
    : session_(session), surface_producer_(surface_producer) {
  FML_DCHECK(surface_producer_ != nullptr);
}

58 59
void SceneUpdateContext::CreateFrame(
    std::unique_ptr<scenic::EntityNode> entity_node,
60
    std::unique_ptr<scenic::ShapeNode> shape_node,
61 62 63 64 65
    const SkRRect& rrect,
    SkColor color,
    const SkRect& paint_bounds,
    std::vector<Layer*> paint_layers,
    Layer* layer) {
66
  // Frames always clip their children.
67 68
  SetEntityNodeClipPlanes(entity_node.get(), rrect.getBounds());
  // TODO(SCN-1274): AddPart() and SetClip() will be deleted.
69
  entity_node->SetClip(0u, true /* clip to self */);
70

71 72 73
  // We don't need a shape if the frame is zero size.
  if (rrect.isEmpty())
    return;
74

75 76
  // Add a part which represents the frame's geometry for clipping purposes
  // and possibly for its texture.
77
  // TODO(SCN-137): Need to be able to express the radii as vectors.
78
  SkRect shape_bounds = rrect.getBounds();
79
  scenic::RoundedRectangle shape(
80 81 82 83 84 85 86
      session_,                                      // session
      rrect.width(),                                 // width
      rrect.height(),                                // height
      rrect.radii(SkRRect::kUpperLeft_Corner).x(),   // top_left_radius
      rrect.radii(SkRRect::kUpperRight_Corner).x(),  // top_right_radius
      rrect.radii(SkRRect::kLowerRight_Corner).x(),  // bottom_right_radius
      rrect.radii(SkRRect::kLowerLeft_Corner).x()    // bottom_left_radius
87
  );
88
  shape_node->SetShape(shape);
89 90 91
  shape_node->SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
                             shape_bounds.height() * 0.5f + shape_bounds.top(),
                             0.f);
92

93 94 95
  // Check whether the painted layers will be visible.
  if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds))
    paint_layers.clear();
96

97 98
  // Check whether a solid color will suffice.
  if (paint_layers.empty()) {
99
    SetShapeColor(*shape_node, color);
100 101 102
    return;
  }

103
  // Apply current metrics and transformation scale factors.
104 105
  const float scale_x = ScaleX();
  const float scale_y = ScaleY();
106

107
  // Apply a texture to the whole shape.
108
  SetShapeTextureOrColor(*shape_node, color, scale_x, scale_y, shape_bounds,
109 110
                         std::move(paint_layers), layer,
                         std::move(entity_node));
111 112
}

113
void SceneUpdateContext::SetShapeTextureOrColor(
114
    scenic::ShapeNode& shape_node,
115 116 117 118
    SkColor color,
    SkScalar scale_x,
    SkScalar scale_y,
    const SkRect& paint_bounds,
119 120 121
    std::vector<Layer*> paint_layers,
    Layer* layer,
    std::unique_ptr<scenic::EntityNode> entity_node) {
122
  scenic::Image* image = GenerateImageIfNeeded(
123 124
      color, scale_x, scale_y, paint_bounds, std::move(paint_layers), layer,
      std::move(entity_node));
125
  if (image != nullptr) {
126
    scenic::Material material(session_);
127 128 129 130 131 132
    material.SetTexture(*image);
    shape_node.SetMaterial(material);
    return;
  }

  SetShapeColor(shape_node, color);
133 134
}

135
void SceneUpdateContext::SetShapeColor(scenic::ShapeNode& shape_node,
136 137 138 139
                                       SkColor color) {
  if (SkColorGetA(color) == 0)
    return;

140
  scenic::Material material(session_);
141 142 143
  material.SetColor(SkColorGetR(color), SkColorGetG(color), SkColorGetB(color),
                    SkColorGetA(color));
  shape_node.SetMaterial(material);
144 145
}

146
scenic::Image* SceneUpdateContext::GenerateImageIfNeeded(
147 148 149 150
    SkColor color,
    SkScalar scale_x,
    SkScalar scale_y,
    const SkRect& paint_bounds,
151 152 153
    std::vector<Layer*> paint_layers,
    Layer* layer,
    std::unique_ptr<scenic::EntityNode> entity_node) {
154 155 156 157 158 159 160 161 162
  // Bail if there's nothing to paint.
  if (paint_layers.empty())
    return nullptr;

  // Bail if the physical bounds are empty after rounding.
  SkISize physical_size = SkISize::Make(paint_bounds.width() * scale_x,
                                        paint_bounds.height() * scale_y);
  if (physical_size.isEmpty())
    return nullptr;
163

164
  // Acquire a surface from the surface producer and register the paint tasks.
165
  std::unique_ptr<SurfaceProducerSurface> surface =
166 167 168 169 170 171
      surface_producer_->ProduceSurface(
          physical_size,
          LayerRasterCacheKey(
              // Root frame has a nullptr layer
              layer ? layer->unique_id() : 0, Matrix()),
          std::move(entity_node));
172 173

  if (!surface) {
174
    FML_LOG(ERROR) << "Could not acquire a surface from the surface producer "
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
                      "of size: "
                   << physical_size.width() << "x" << physical_size.height();
    return nullptr;
  }

  auto image = surface->GetImage();

  // Enqueue the paint task.
  paint_tasks_.push_back({.surface = std::move(surface),
                          .left = paint_bounds.left(),
                          .top = paint_bounds.top(),
                          .scale_x = scale_x,
                          .scale_y = scale_y,
                          .background_color = color,
                          .layers = std::move(paint_layers)});
  return image;
}

193 194
std::vector<
    std::unique_ptr<flutter::SceneUpdateContext::SurfaceProducerSurface>>
195
SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
196
  TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks");
197
  std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces_to_submit;
198
  for (auto& task : paint_tasks_) {
199
    FML_DCHECK(task.surface);
200
    SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
201
    Layer::PaintContext context = {canvas,
202
                                   canvas,
203
                                   frame.gr_context(),
204
                                   nullptr,
205 206
                                   frame.context().raster_time(),
                                   frame.context().ui_time(),
207 208 209
                                   frame.context().texture_registry(),
                                   &frame.context().raster_cache(),
                                   false};
210 211 212 213
    canvas->restoreToCount(1);
    canvas->save();
    canvas->clear(task.background_color);
    canvas->scale(task.scale_x, task.scale_y);
214
    canvas->translate(-task.left, -task.top);
215
    for (Layer* layer : task.layers) {
216
      layer->Paint(context);
217 218
    }
    surfaces_to_submit.emplace_back(std::move(task.surface));
219 220
  }
  paint_tasks_.clear();
221
  return surfaces_to_submit;
222 223
}

224
SceneUpdateContext::Entity::Entity(SceneUpdateContext& context)
225 226
    : context_(context), previous_entity_(context.top_entity_) {
  entity_node_ptr_ = std::make_unique<scenic::EntityNode>(context.session());
227 228 229
  shape_node_ptr_ = std::make_unique<scenic::ShapeNode>(context.session());
  // TODO(SCN-1274): AddPart() and SetClip() will be deleted.
  entity_node_ptr_->AddPart(*shape_node_ptr_);
230
  if (previous_entity_)
231
    previous_entity_->entity_node_ptr_->AddChild(*entity_node_ptr_);
232 233 234 235
  context.top_entity_ = this;
}

SceneUpdateContext::Entity::~Entity() {
236
  FML_DCHECK(context_.top_entity_ == this);
237 238 239 240 241
  context_.top_entity_ = previous_entity_;
}

SceneUpdateContext::Transform::Transform(SceneUpdateContext& context,
                                         const SkMatrix& transform)
242 243 244 245
    : Entity(context),
      previous_scale_x_(context.top_scale_x_),
      previous_scale_y_(context.top_scale_y_) {
  if (!transform.isIdentity()) {
246
    // TODO(SCN-192): The perspective and shear components in the matrix
247 248 249
    // are not handled correctly.
    MatrixDecomposition decomposition(transform);
    if (decomposition.IsValid()) {
250 251
      entity_node().SetTranslation(decomposition.translation().x(),  //
                                   decomposition.translation().y(),  //
252
                                   -decomposition.translation().z()  //
253
      );
254 255 256 257

      entity_node().SetScale(decomposition.scale().x(),  //
                             decomposition.scale().y(),  //
                             decomposition.scale().z()   //
258
      );
259 260 261 262 263 264 265
      context.top_scale_x_ *= decomposition.scale().x();
      context.top_scale_y_ *= decomposition.scale().y();

      entity_node().SetRotation(decomposition.rotation().fData[0],  //
                                decomposition.rotation().fData[1],  //
                                decomposition.rotation().fData[2],  //
                                decomposition.rotation().fData[3]   //
266
      );
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
    }
  }
}

SceneUpdateContext::Transform::Transform(SceneUpdateContext& context,
                                         float scale_x,
                                         float scale_y,
                                         float scale_z)
    : Entity(context),
      previous_scale_x_(context.top_scale_x_),
      previous_scale_y_(context.top_scale_y_) {
  if (scale_x != 1.f || scale_y != 1.f || scale_z != 1.f) {
    entity_node().SetScale(scale_x, scale_y, scale_z);
    context.top_scale_x_ *= scale_x;
    context.top_scale_y_ *= scale_y;
282 283 284
  }
}

285 286 287 288
SceneUpdateContext::Transform::~Transform() {
  context().top_scale_x_ = previous_scale_x_;
  context().top_scale_y_ = previous_scale_y_;
}
289 290 291 292

SceneUpdateContext::Frame::Frame(SceneUpdateContext& context,
                                 const SkRRect& rrect,
                                 SkColor color,
293 294 295
                                 float local_elevation,
                                 float world_elevation,
                                 float depth,
296
                                 Layer* layer)
297 298 299
    : Entity(context),
      rrect_(rrect),
      color_(color),
300 301
      paint_bounds_(SkRect::MakeEmpty()),
      layer_(layer) {
302 303 304 305 306 307 308 309 310 311 312
  if (depth > -1 && world_elevation > depth) {
    // TODO(mklim): Deal with bounds overflow more elegantly. We'd like to be
    // able to have developers specify the behavior here to alternatives besides
    // clamping, like normalization on some arbitrary curve.

    // Clamp the local z coordinate at our max bound. Take into account the
    // parent z position here to fix clamping in cases where the child is
    // overflowing because of its parents.
    const float parent_elevation = world_elevation - local_elevation;
    local_elevation = depth - parent_elevation;
  }
313 314 315
  if (local_elevation != 0.0) {
    entity_node().SetTranslation(0.f, 0.f, -local_elevation);
  }
316 317 318
}

SceneUpdateContext::Frame::~Frame() {
319 320
  context().CreateFrame(std::move(entity_node_ptr()),
                        std::move(shape_node_ptr()), rrect_, color_,
321
                        paint_bounds_, std::move(paint_layers_), layer_);
322 323
}

324
void SceneUpdateContext::Frame::AddPaintLayer(Layer* layer) {
325
  FML_DCHECK(layer->needs_painting());
326 327 328 329
  paint_layers_.push_back(layer);
  paint_bounds_.join(layer->paint_bounds());
}

330 331 332 333 334
SceneUpdateContext::Clip::Clip(SceneUpdateContext& context,
                               scenic::Shape& shape,
                               const SkRect& shape_bounds)
    : Entity(context) {
  shape_node().SetShape(shape);
335 336 337
  shape_node().SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
                              shape_bounds.height() * 0.5f + shape_bounds.top(),
                              0.f);
338 339 340 341 342
  entity_node().SetClip(0u, true /* clip to self */);

  SetEntityNodeClipPlanes(&entity_node(), shape_bounds);
}

343
}  // namespace flutter