rasterizer.cc 8.6 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "flutter/shell/common/rasterizer.h"
6

7 8 9 10 11 12
#include <utility>

#include "third_party/skia/include/core/SkEncodedImageFormat.h"
#include "third_party/skia/include/core/SkImageEncoder.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "third_party/skia/include/core/SkSurface.h"
13
#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
14
#include "third_party/skia/include/utils/SkBase64.h"
15

C
Chinmay Garde 已提交
16 17 18 19
#ifdef ERROR
#undef ERROR
#endif

20 21
namespace shell {

22
Rasterizer::Rasterizer(blink::TaskRunners task_runners)
23 24 25 26 27 28 29 30 31
    : Rasterizer(std::move(task_runners),
                 std::make_unique<flow::CompositorContext>()) {}

Rasterizer::Rasterizer(
    blink::TaskRunners task_runners,
    std::unique_ptr<flow::CompositorContext> compositor_context)
    : task_runners_(std::move(task_runners)),
      compositor_context_(std::move(compositor_context)),
      weak_factory_(this) {
32
  FML_DCHECK(compositor_context_);
33
}
34

35
Rasterizer::~Rasterizer() = default;
36

37
fml::WeakPtr<Rasterizer> Rasterizer::GetWeakPtr() const {
38
  return weak_factory_.GetWeakPtr();
39 40 41 42
}

void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
  surface_ = std::move(surface);
43
  compositor_context_->OnGrContextCreated();
44 45 46
}

void Rasterizer::Teardown() {
47
  compositor_context_->OnGrContextDestroyed();
48 49 50 51 52
  surface_.reset();
  last_layer_tree_.reset();
}

flow::TextureRegistry* Rasterizer::GetTextureRegistry() {
53
  return &compositor_context_->texture_registry();
54 55 56 57 58 59 60 61 62 63 64 65 66 67
}

flow::LayerTree* Rasterizer::GetLastLayerTree() {
  return last_layer_tree_.get();
}

void Rasterizer::DrawLastLayerTree() {
  if (!last_layer_tree_ || !surface_) {
    return;
  }
  DrawToSurface(*last_layer_tree_);
}

void Rasterizer::Draw(
68
    fml::RefPtr<flutter::Pipeline<flow::LayerTree>> pipeline) {
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
  TRACE_EVENT0("flutter", "GPURasterizer::Draw");

  flutter::Pipeline<flow::LayerTree>::Consumer consumer =
      std::bind(&Rasterizer::DoDraw, this, std::placeholders::_1);

  // Consume as many pipeline items as possible. But yield the event loop
  // between successive tries.
  switch (pipeline->Consume(consumer)) {
    case flutter::PipelineConsumeResult::MoreAvailable: {
      task_runners_.GetGPUTaskRunner()->PostTask(
          [weak_this = weak_factory_.GetWeakPtr(), pipeline]() {
            if (weak_this) {
              weak_this->Draw(pipeline);
            }
          });
      break;
    }
    default:
      break;
  }
}

void Rasterizer::DoDraw(std::unique_ptr<flow::LayerTree> layer_tree) {
  if (!layer_tree || !surface_) {
    return;
  }

  if (DrawToSurface(*layer_tree)) {
    last_layer_tree_ = std::move(layer_tree);
  }
}

bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) {
102
  FML_DCHECK(surface_);
103 104 105 106 107 108 109 110 111 112

  auto frame = surface_->AcquireFrame(layer_tree.frame_size());

  if (frame == nullptr) {
    return false;
  }

  // There is no way for the compositor to know how long the layer tree
  // construction took. Fortunately, the layer tree does. Grab that time
  // for instrumentation.
113
  compositor_context_->engine_time().SetLapTime(layer_tree.construction_time());
114

115 116
  auto canvas = frame->SkiaCanvas();

117 118
  auto compositor_frame = compositor_context_->AcquireFrame(
      surface_->GetContext(), canvas, surface_->GetRootTransformation(), true);
119 120 121 122

  if (canvas) {
    canvas->clear(SK_ColorBLACK);
  }
123 124 125 126 127 128 129 130 131 132

  if (compositor_frame && compositor_frame->Raster(layer_tree, false)) {
    frame->Submit();
    FireNextFrameCallbackIfPresent();
    return true;
  }

  return false;
}

133 134 135
static sk_sp<SkPicture> ScreenshotLayerTreeAsPicture(
    flow::LayerTree* tree,
    flow::CompositorContext& compositor_context) {
136
  FML_DCHECK(tree != nullptr);
137 138 139 140
  SkPictureRecorder recorder;
  recorder.beginRecording(
      SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height()));

141 142 143 144 145 146
  SkMatrix root_surface_transformation;
  root_surface_transformation.reset();

  auto frame =
      compositor_context.AcquireFrame(nullptr, recorder.getRecordingCanvas(),
                                      root_surface_transformation, false);
147 148 149 150 151 152

  frame->Raster(*tree, true);

  return recorder.finishRecordingAsPicture();
}

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
static sk_sp<SkSurface> CreateSnapshotSurface(GrContext* surface_context,
                                              const SkISize& size) {
  const auto image_info = SkImageInfo::MakeN32Premul(size);
  if (surface_context) {
    // There is a rendering surface that may contain textures that are going to
    // be referenced in the layer tree about to be drawn.
    return SkSurface::MakeRenderTarget(surface_context,  //
                                       SkBudgeted::kNo,  //
                                       image_info        //
    );
  }

  // There is no rendering surface, assume no GPU textures are present and
  // create a raster surface.
  return SkSurface::MakeRaster(image_info);
}

170 171 172 173 174
static sk_sp<SkData> ScreenshotLayerTreeAsImage(
    flow::LayerTree* tree,
    flow::CompositorContext& compositor_context,
    GrContext* surface_context,
    bool compressed) {
175 176 177 178 179
  // Attempt to create a snapshot surface depending on whether we have access to
  // a valid GPU rendering context.
  auto snapshot_surface =
      CreateSnapshotSurface(surface_context, tree->frame_size());
  if (snapshot_surface == nullptr) {
180
    FML_LOG(ERROR) << "Screenshot: unable to create snapshot surface";
181 182
    return nullptr;
  }
183 184 185

  // Draw the current layer tree into the snapshot surface.
  auto canvas = snapshot_surface->getCanvas();
186 187 188 189 190 191 192 193

  // There is no root surface transformation for the screenshot layer. Reset the
  // matrix to identity.
  SkMatrix root_surface_transformation;
  root_surface_transformation.reset();

  auto frame = compositor_context.AcquireFrame(
      surface_context, canvas, root_surface_transformation, false);
194
  canvas->clear(SK_ColorBLACK);
195
  frame->Raster(*tree, true);
196
  canvas->flush();
197 198 199 200

  // Prepare an image from the surface, this image may potentially be on th GPU.
  auto potentially_gpu_snapshot = snapshot_surface->makeImageSnapshot();
  if (!potentially_gpu_snapshot) {
201
    FML_LOG(ERROR) << "Screenshot: unable to make image screenshot";
202 203 204 205 206 207
    return nullptr;
  }

  // Copy the GPU image snapshot into CPU memory.
  auto cpu_snapshot = potentially_gpu_snapshot->makeRasterImage();
  if (!cpu_snapshot) {
208
    FML_LOG(ERROR) << "Screenshot: unable to make raster image";
209 210 211
    return nullptr;
  }

212
  // If the caller want the pixels to be compressed, there is a Skia utility to
213
  // compress to PNG. Use that.
214
  if (compressed) {
215 216 217 218 219 220
    return cpu_snapshot->encodeToData();
  }

  // Copy it into a bitmap and return the same.
  SkPixmap pixmap;
  if (!cpu_snapshot->peekPixels(&pixmap)) {
221
    FML_LOG(ERROR) << "Screenshot: unable to obtain bitmap pixels";
222
    return nullptr;
223
  }
224 225

  return SkData::MakeWithCopy(pixmap.addr32(), pixmap.computeByteSize());
226 227 228 229 230 231 232
}

Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
    Rasterizer::ScreenshotType type,
    bool base64_encode) {
  auto layer_tree = GetLastLayerTree();
  if (layer_tree == nullptr) {
233
    FML_LOG(ERROR) << "Last layer tree was null when screenshotting.";
234 235 236 237 238
    return {};
  }

  sk_sp<SkData> data = nullptr;

239 240
  GrContext* surface_context = surface_ ? surface_->GetContext() : nullptr;

241 242
  switch (type) {
    case ScreenshotType::SkiaPicture:
243 244
      data = ScreenshotLayerTreeAsPicture(layer_tree, *compositor_context_)
                 ->serialize();
245 246
      break;
    case ScreenshotType::UncompressedImage:
247 248
      data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
                                        surface_context, false);
249 250
      break;
    case ScreenshotType::CompressedImage:
251 252
      data = ScreenshotLayerTreeAsImage(layer_tree, *compositor_context_,
                                        surface_context, true);
253 254 255 256
      break;
  }

  if (data == nullptr) {
257
    FML_LOG(ERROR) << "Screenshot data was null.";
258 259 260 261 262 263 264 265 266 267 268 269 270
    return {};
  }

  if (base64_encode) {
    size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr);
    auto b64_data = SkData::MakeUninitialized(b64_size);
    SkBase64::Encode(data->data(), data->size(), b64_data->writable_data());
    return Rasterizer::Screenshot{b64_data, layer_tree->frame_size()};
  }

  return Rasterizer::Screenshot{data, layer_tree->frame_size()};
}

271
void Rasterizer::SetNextFrameCallback(fml::closure callback) {
272 273 274 275 276 277 278 279 280 281 282 283 284
  next_frame_callback_ = callback;
}

void Rasterizer::FireNextFrameCallbackIfPresent() {
  if (!next_frame_callback_) {
    return;
  }
  // It is safe for the callback to set a new callback.
  auto callback = next_frame_callback_;
  next_frame_callback_ = nullptr;
  callback();
}

285
}  // namespace shell