scene_update_context.cc 11.5 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4 5 6
// 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"

7
#include "flutter/flow/export_node.h"
8
#include "flutter/flow/layers/layer.h"
9
#include "flutter/flow/matrix_decomposition.h"
10
#include "flutter/fml/trace_event.h"
11 12 13

namespace flow {

14
SceneUpdateContext::SceneUpdateContext(scenic::Session* session,
15
                                       SurfaceProducer* surface_producer)
16
    : session_(session), surface_producer_(surface_producer) {
17
  FML_DCHECK(surface_producer_ != nullptr);
18
}
19

20
SceneUpdateContext::~SceneUpdateContext() {
21
  // Release Mozart session resources for all ExportNodes.
22 23 24 25
  for (auto export_node : export_nodes_) {
    export_node->Dispose(false);
  }
};
26

27 28 29
void SceneUpdateContext::AddChildScene(ExportNode* export_node,
                                       SkPoint offset,
                                       bool hit_testable) {
30
  FML_DCHECK(top_entity_);
31

32
  export_node->Bind(*this, top_entity_->entity_node(), offset, hit_testable);
33 34
}

35 36 37 38 39 40 41 42
void SceneUpdateContext::AddExportNode(ExportNode* export_node) {
  export_nodes_.insert(export_node);  // Might already have been added.
}

void SceneUpdateContext::RemoveExportNode(ExportNode* export_node) {
  export_nodes_.erase(export_node);
}

43
void SceneUpdateContext::CreateFrame(scenic::EntityNode& entity_node,
44 45 46 47 48 49
                                     const SkRRect& rrect,
                                     SkColor color,
                                     const SkRect& paint_bounds,
                                     std::vector<Layer*> paint_layers) {
  // Frames always clip their children.
  entity_node.SetClip(0u, true /* clip to self */);
50

51 52 53
  // We don't need a shape if the frame is zero size.
  if (rrect.isEmpty())
    return;
54

55 56 57 58
  // Add a part which represents the frame's geometry for clipping purposes
  // and possibly for its texture.
  // TODO(MZ-137): Need to be able to express the radii as vectors.
  SkRect shape_bounds = rrect.getBounds();
59
  scenic::RoundedRectangle shape(
60 61 62 63 64 65 66
      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
67
  );
68
  scenic::ShapeNode shape_node(session_);
69 70 71 72 73
  shape_node.SetShape(shape);
  shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
                            shape_bounds.height() * 0.5f + shape_bounds.top(),
                            0.f);
  entity_node.AddPart(shape_node);
74

75 76 77
  // Check whether the painted layers will be visible.
  if (paint_bounds.isEmpty() || !paint_bounds.intersects(shape_bounds))
    paint_layers.clear();
78

79 80 81 82 83 84
  // Check whether a solid color will suffice.
  if (paint_layers.empty()) {
    SetShapeColor(shape_node, color);
    return;
  }

85 86 87 88
  // Apply current metrics and transformation scale factors.
  const float scale_x = metrics_->scale_x * top_scale_x_;
  const float scale_y = metrics_->scale_y * top_scale_y_;

89 90 91 92 93 94 95
  // If the painted area only covers a portion of the frame then we can
  // reduce the texture size by drawing just that smaller area.
  SkRect inner_bounds = shape_bounds;
  inner_bounds.intersect(paint_bounds);
  if (inner_bounds != shape_bounds && rrect.contains(inner_bounds)) {
    SetShapeColor(shape_node, color);

96
    scenic::Rectangle inner_shape(session_, inner_bounds.width(),
97
                                  inner_bounds.height());
98
    scenic::ShapeNode inner_node(session_);
99 100 101 102 103 104 105 106
    inner_node.SetShape(inner_shape);
    inner_node.SetTranslation(inner_bounds.width() * 0.5f + inner_bounds.left(),
                              inner_bounds.height() * 0.5f + inner_bounds.top(),
                              0.f);
    entity_node.AddPart(inner_node);
    SetShapeTextureOrColor(inner_node, color, scale_x, scale_y, inner_bounds,
                           std::move(paint_layers));
    return;
107 108
  }

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

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

  SetShapeColor(shape_node, color);
131 132
}

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

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

144
scenic::Image* SceneUpdateContext::GenerateImageIfNeeded(
145 146 147 148 149 150 151 152 153 154 155 156 157 158
    SkColor color,
    SkScalar scale_x,
    SkScalar scale_y,
    const SkRect& paint_bounds,
    std::vector<Layer*> paint_layers) {
  // 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;
159

160 161 162 163
  // Acquire a surface from the surface producer and register the paint tasks.
  auto surface = surface_producer_->ProduceSurface(physical_size);

  if (!surface) {
164
    FML_LOG(ERROR) << "Could not acquire a surface from the surface producer "
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
                      "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;
}

std::vector<std::unique_ptr<flow::SceneUpdateContext::SurfaceProducerSurface>>
SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) {
  TRACE_EVENT0("flutter", "SceneUpdateContext::ExecutePaintTasks");
  std::vector<std::unique_ptr<SurfaceProducerSurface>> surfaces_to_submit;
187
  for (auto& task : paint_tasks_) {
188
    FML_DCHECK(task.surface);
189
    SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas();
190 191
    Layer::PaintContext context = {canvas,
                                   nullptr,
192
                                   frame.context().frame_time(),
A
Adam Barth 已提交
193
                                   frame.context().engine_time(),
194 195 196
                                   frame.context().texture_registry(),
                                   &frame.context().raster_cache(),
                                   false};
197 198 199 200
    canvas->restoreToCount(1);
    canvas->save();
    canvas->clear(task.background_color);
    canvas->scale(task.scale_x, task.scale_y);
201
    canvas->translate(-task.left, -task.top);
202
    for (Layer* layer : task.layers) {
203
      layer->Paint(context);
204 205
    }
    surfaces_to_submit.emplace_back(std::move(task.surface));
206 207
  }
  paint_tasks_.clear();
208
  return surfaces_to_submit;
209 210
}

211 212 213 214 215 216 217 218 219 220
SceneUpdateContext::Entity::Entity(SceneUpdateContext& context)
    : context_(context),
      previous_entity_(context.top_entity_),
      entity_node_(context.session()) {
  if (previous_entity_)
    previous_entity_->entity_node_.AddChild(entity_node_);
  context.top_entity_ = this;
}

SceneUpdateContext::Entity::~Entity() {
221
  FML_DCHECK(context_.top_entity_ == this);
222 223 224 225
  context_.top_entity_ = previous_entity_;
}

SceneUpdateContext::Clip::Clip(SceneUpdateContext& context,
226
                               scenic::Shape& shape,
227 228
                               const SkRect& shape_bounds)
    : Entity(context) {
229
  scenic::ShapeNode shape_node(context.session());
230 231 232 233 234 235 236 237 238 239
  shape_node.SetShape(shape);
  shape_node.SetTranslation(shape_bounds.width() * 0.5f + shape_bounds.left(),
                            shape_bounds.height() * 0.5f + shape_bounds.top(),
                            0.f);

  entity_node().AddPart(shape_node);
  entity_node().SetClip(0u, true /* clip to self */);
}

SceneUpdateContext::Clip::~Clip() = default;
240

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

      entity_node().SetScale(decomposition.scale().x(),  //
                             decomposition.scale().y(),  //
                             decomposition.scale().z()   //
259
      );
260 261 262 263 264 265 266
      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]   //
267
      );
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    }
  }
}

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;
283 284 285
  }
}

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

SceneUpdateContext::Frame::Frame(SceneUpdateContext& context,
                                 const SkRRect& rrect,
                                 SkColor color,
294
                                 float elevation)
295 296 297 298
    : Entity(context),
      rrect_(rrect),
      color_(color),
      paint_bounds_(SkRect::MakeEmpty()) {
299 300
  if (elevation != 0.0)
    entity_node().SetTranslation(0.f, 0.f, elevation);
301 302 303
}

SceneUpdateContext::Frame::~Frame() {
304 305
  context().CreateFrame(entity_node(), rrect_, color_, paint_bounds_,
                        std::move(paint_layers_));
306 307 308
}

void SceneUpdateContext::Frame::AddPaintedLayer(Layer* layer) {
309
  FML_DCHECK(layer->needs_painting());
310 311 312 313 314
  paint_layers_.push_back(layer);
  paint_bounds_.join(layer->paint_bounds());
}

}  // namespace flow