blob: 7639dfdb029a143ab9631811bd4799ad4b0f907c [file] [log] [blame]
Brian Salomon06c9e292021-04-29 14:10:23 -04001/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "tools/MSKPPlayer.h"
9
10#include "include/core/SkCanvas.h"
11#include "include/core/SkCanvasVirtualEnforcer.h"
12#include "include/core/SkPicture.h"
13#include "include/core/SkPictureRecorder.h"
14#include "include/core/SkSurface.h"
Brian Salomon31fddc32021-04-30 13:08:55 -040015#include "include/gpu/GrDirectContext.h"
Brian Salomon06c9e292021-04-29 14:10:23 -040016#include "include/private/SkTArray.h"
17#include "include/utils/SkNoDrawCanvas.h"
18#include "src/core/SkCanvasPriv.h"
19#include "src/core/SkTLazy.h"
20#include "src/utils/SkMultiPictureDocument.h"
21#include "tools/SkSharingProc.h"
22
Brian Salomon06c9e292021-04-29 14:10:23 -040023///////////////////////////////////////////////////////////////////////////////
24
25// Base Cmd struct.
26struct MSKPPlayer::Cmd {
27 virtual ~Cmd() = default;
Brian Salomon33ec61132021-05-12 12:03:02 -040028 virtual bool isFullRedraw(SkCanvas*) const = 0;
Brian Salomon06c9e292021-04-29 14:10:23 -040029 virtual void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const = 0;
Brian Salomon33ec61132021-05-12 12:03:02 -040030 // If this command draws another layer, return it's ID. Otherwise, -1.
31 virtual int layerID() const { return -1; }
Brian Salomon06c9e292021-04-29 14:10:23 -040032};
33
34// Draws a SkPicture.
35struct MSKPPlayer::PicCmd : Cmd {
36 sk_sp<SkPicture> fContent;
Brian Salomon33ec61132021-05-12 12:03:02 -040037 SkIRect fClipRect = SkIRect::MakeEmpty(); // clip for picture (no clip if empty).
38
39 bool isFullRedraw(SkCanvas* canvas) const override {
40 if (fClipRect.isEmpty()) {
41 return false;
42 }
43 return fClipRect.contains(SkIRect::MakeSize(canvas->getBaseLayerSize()));
44 }
Brian Salomon06c9e292021-04-29 14:10:23 -040045
46 void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const override {
Brian Salomon33ec61132021-05-12 12:03:02 -040047 if (!fClipRect.isEmpty()) {
48 canvas->save();
49 canvas->clipIRect(fClipRect);
50 }
Brian Salomon06c9e292021-04-29 14:10:23 -040051 canvas->drawPicture(fContent.get());
Brian Salomon33ec61132021-05-12 12:03:02 -040052 if (!fClipRect.isEmpty()) {
53 canvas->restore();
54 }
Brian Salomon06c9e292021-04-29 14:10:23 -040055 }
56};
57
58// Draws another layer. Stores the ID of the layer to draw and what command index on that
59// layer should be current when the layer is drawn. The layer contents are updated to the
60// stored command index before the layer is drawn.
61struct MSKPPlayer::DrawLayerCmd : Cmd {
62 int fLayerId;
63 size_t fLayerCmdCnt;
64 SkRect fSrcRect;
65 SkRect fDstRect;
66 SkSamplingOptions fSampling;
67 SkCanvas::SrcRectConstraint fConstraint;
68 SkTLazy<SkPaint> fPaint;
69
Brian Salomon33ec61132021-05-12 12:03:02 -040070 bool isFullRedraw(SkCanvas* canvas) const override { return false; }
Brian Salomon06c9e292021-04-29 14:10:23 -040071 void draw(SkCanvas* canvas, const LayerMap&, LayerStateMap*) const override;
Brian Salomon33ec61132021-05-12 12:03:02 -040072 int layerID() const override { return fLayerId; }
Brian Salomon06c9e292021-04-29 14:10:23 -040073};
74
75void MSKPPlayer::DrawLayerCmd::draw(SkCanvas* canvas,
76 const LayerMap& layerMap,
77 LayerStateMap* layerStateMap) const {
Brian Osman68556bc2021-07-30 15:24:22 -040078 const LayerCmds& layer = layerMap.at(fLayerId);
Brian Salomon06c9e292021-04-29 14:10:23 -040079 LayerState* layerState = &(*layerStateMap)[fLayerId];
80 if (!layerState->fSurface) {
81 layerState->fCurrCmd = 0;
Brian Salomon31fddc32021-04-30 13:08:55 -040082 layerState->fSurface = MSKPPlayer::MakeSurfaceForLayer(layer, canvas);
Brian Salomon06c9e292021-04-29 14:10:23 -040083 if (!layerState->fSurface) {
84 SkDebugf("Couldn't create surface for layer");
85 return;
86 }
87 }
88 size_t cmd = layerState->fCurrCmd;
89 if (cmd > fLayerCmdCnt) {
90 // If the layer contains contents from later commands then replay from the beginning.
91 cmd = 0;
92 }
93 SkCanvas* layerCanvas = layerState->fSurface->getCanvas();
Brian Salomon33ec61132021-05-12 12:03:02 -040094 // Check if there is a full redraw between cmd and fLayerCmdCnt and if so jump to it and ensure
95 // we clear the canvas if starting from a full redraw.
96 for (size_t checkCmd = fLayerCmdCnt - 1; checkCmd > cmd; --checkCmd) {
97 if (layer.fCmds[checkCmd]->isFullRedraw(layerCanvas)) {
98 cmd = checkCmd;
99 break;
100 }
101 }
Brian Salomon06c9e292021-04-29 14:10:23 -0400102 for (; cmd < fLayerCmdCnt; ++cmd) {
Brian Salomon33ec61132021-05-12 12:03:02 -0400103 if (cmd == 0 || layer.fCmds[cmd]->isFullRedraw(layerCanvas)) {
104 layerState->fSurface->getCanvas()->clear(SK_ColorTRANSPARENT);
105 }
Brian Salomon06c9e292021-04-29 14:10:23 -0400106 layer.fCmds[cmd]->draw(layerCanvas, layerMap, layerStateMap);
107 }
Brian Salomon33ec61132021-05-12 12:03:02 -0400108 layerState->fCurrCmd = fLayerCmdCnt;
Brian Salomon06c9e292021-04-29 14:10:23 -0400109 const SkPaint* paint = fPaint.isValid() ? fPaint.get() : nullptr;
110 canvas->drawImageRect(layerState->fSurface->makeImageSnapshot(),
111 fSrcRect,
112 fDstRect,
113 fSampling,
114 paint,
115 fConstraint);
116}
117
118///////////////////////////////////////////////////////////////////////////////
119
120class MSKPPlayer::CmdRecordCanvas : public SkCanvasVirtualEnforcer<SkCanvas> {
121public:
Brian Osman68556bc2021-07-30 15:24:22 -0400122 CmdRecordCanvas(LayerCmds* dst, LayerMap* offscreenLayers, const SkIRect* clipRect = nullptr)
Brian Salomon06c9e292021-04-29 14:10:23 -0400123 : fDst(dst), fOffscreenLayers(offscreenLayers) {
Brian Salomon33ec61132021-05-12 12:03:02 -0400124 if (clipRect) {
125 fClipRect = *clipRect;
126 }
Brian Salomon06c9e292021-04-29 14:10:23 -0400127 fRecorder.beginRecording(SkRect::Make(dst->fDimensions));
128 }
129 ~CmdRecordCanvas() override { this->recordPicCmd(); }
130
131protected:
132 void onDrawPaint(const SkPaint& paint) override {
133 fRecorder.getRecordingCanvas()->drawPaint(paint);
134 }
135
136 void onDrawBehind(const SkPaint& paint) override {
137 SkCanvasPriv::DrawBehind(fRecorder.getRecordingCanvas(), paint);
138 }
139
140 void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
141 fRecorder.getRecordingCanvas()->drawRect(rect, paint);
142 }
143
144 void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
145 fRecorder.getRecordingCanvas()->drawRRect(rrect, paint);
146 }
147
148 void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
149 fRecorder.getRecordingCanvas()->drawDRRect(outer, inner, paint);
150 }
151
152 void onDrawOval(const SkRect& rect, const SkPaint& paint) override {
153 fRecorder.getRecordingCanvas()->drawOval(rect, paint);
154 }
155
156 void onDrawArc(const SkRect& rect,
157 SkScalar startAngle,
158 SkScalar sweepAngle,
159 bool useCenter,
160 const SkPaint& paint) override {
161 fRecorder.getRecordingCanvas()->drawArc(rect, startAngle, sweepAngle, useCenter, paint);
162 }
163
164 void onDrawPath(const SkPath& path, const SkPaint& paint) override {
165 fRecorder.getRecordingCanvas()->drawPath(path, paint);
166 }
167
168 void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
169 fRecorder.getRecordingCanvas()->drawRegion(region, paint);
170 }
171
172 void onDrawTextBlob(const SkTextBlob* blob,
173 SkScalar x,
174 SkScalar y,
175 const SkPaint& paint) override {
176 fRecorder.getRecordingCanvas()->drawTextBlob(blob, x, y, paint);
177 }
178
179 void onDrawPatch(const SkPoint cubics[12],
180 const SkColor colors[4],
181 const SkPoint texCoords[4],
182 SkBlendMode mode,
183 const SkPaint& paint) override {
184 fRecorder.getRecordingCanvas()->drawPatch(cubics, colors, texCoords, mode, paint);
185 }
186
187 void onDrawPoints(SkCanvas::PointMode mode,
188 size_t count,
189 const SkPoint pts[],
190 const SkPaint& paint) override {
191 fRecorder.getRecordingCanvas()->drawPoints(mode, count, pts, paint);
192 }
193
194 void onDrawImage2(const SkImage* image,
195 SkScalar dx,
196 SkScalar dy,
197 const SkSamplingOptions& sampling,
198 const SkPaint* paint) override {
199 fRecorder.getRecordingCanvas()->drawImage(image, dx, dy, sampling, paint);
200 }
201
202 void onDrawImageRect2(const SkImage* image,
203 const SkRect& src,
204 const SkRect& dst,
205 const SkSamplingOptions& sampling,
206 const SkPaint* paint,
207 SrcRectConstraint constraint) override {
208 if (fNextDrawImageFromLayerID != -1) {
209 this->recordPicCmd();
210 auto drawLayer = std::make_unique<DrawLayerCmd>();
211 drawLayer->fLayerId = fNextDrawImageFromLayerID;
212 drawLayer->fLayerCmdCnt = fOffscreenLayers->at(fNextDrawImageFromLayerID).fCmds.size();
213 drawLayer->fSrcRect = src;
214 drawLayer->fDstRect = dst;
215 drawLayer->fSampling = sampling;
216 drawLayer->fConstraint = constraint;
217 if (paint) {
218 drawLayer->fPaint.init(*paint);
219 }
220 fDst->fCmds.push_back(std::move(drawLayer));
221 fNextDrawImageFromLayerID = -1;
222 return;
223 }
224 fRecorder.getRecordingCanvas()->drawImageRect(image, src, dst, sampling, paint, constraint);
225 }
226
227 void onDrawImageLattice2(const SkImage* image,
228 const Lattice& lattice,
229 const SkRect& dst,
230 SkFilterMode mode,
231 const SkPaint* paint) override {
232 fRecorder.getRecordingCanvas()->drawImageLattice(image, lattice, dst, mode, paint);
233 }
234
235 void onDrawAtlas2(const SkImage* image,
236 const SkRSXform rsxForms[],
237 const SkRect src[],
238 const SkColor colors[],
239 int count,
240 SkBlendMode mode,
241 const SkSamplingOptions& sampling,
242 const SkRect* cull,
243 const SkPaint* paint) override {
244 fRecorder.getRecordingCanvas()->drawAtlas(image,
245 rsxForms,
246 src,
247 colors,
248 count,
249 mode,
250 sampling,
251 cull,
252 paint);
253 }
254
255 void onDrawEdgeAAImageSet2(const ImageSetEntry imageSet[],
256 int count,
257 const SkPoint dstClips[],
258 const SkMatrix preViewMatrices[],
259 const SkSamplingOptions& sampling,
260 const SkPaint* paint,
261 SrcRectConstraint constraint) override {
262 fRecorder.getRecordingCanvas()->experimental_DrawEdgeAAImageSet(imageSet,
263 count,
264 dstClips,
265 preViewMatrices,
266 sampling,
267 paint,
268 constraint);
269 }
270
271#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
272 void onDrawEdgeAAQuad(const SkRect& rect,
273 const SkPoint clip[4],
274 SkCanvas::QuadAAFlags aaFlags,
275 const SkColor4f& color,
276 SkBlendMode mode) override {}
277#else
278 void onDrawEdgeAAQuad(const SkRect& rect,
279 const SkPoint clip[4],
280 SkCanvas::QuadAAFlags aaFlags,
281 const SkColor4f& color,
282 SkBlendMode mode) override {
283 fRecorder.getRecordingCanvas()->experimental_DrawEdgeAAQuad(rect,
284 clip,
285 aaFlags,
286 color,
287 mode);
288 }
289#endif
290
291 void onDrawAnnotation(const SkRect& rect, const char key[], SkData* value) override {
292 static constexpr char kOffscreenLayerDraw[] = "OffscreenLayerDraw";
293 static constexpr char kSurfaceID[] = "SurfaceID";
294 SkTArray<SkString> tokens;
295 SkStrSplit(key, "|", kStrict_SkStrSplitMode, &tokens);
296 if (tokens.size() == 2) {
297 if (tokens[0].equals(kOffscreenLayerDraw)) {
298 // Indicates that the next drawPicture command contains the SkPicture to render
299 // to the layer identified by the ID. 'rect' indicates the dirty area to update
300 // (and indicates the layer size if this command is introducing a new layer id).
Brian Salomon33ec61132021-05-12 12:03:02 -0400301 fNextDrawPictureToLayerID = std::stoi(tokens[1].c_str());
302 fNextDrawPictureToLayerClipRect = rect.roundOut();
303 if (fOffscreenLayers->find(fNextDrawPictureToLayerID) == fOffscreenLayers->end()) {
304 SkASSERT(fNextDrawPictureToLayerClipRect.left() == 0 &&
305 fNextDrawPictureToLayerClipRect.top() == 0);
306 (*fOffscreenLayers)[fNextDrawPictureToLayerID].fDimensions =
307 fNextDrawPictureToLayerClipRect.size();
Brian Salomon06c9e292021-04-29 14:10:23 -0400308 }
Brian Salomon33ec61132021-05-12 12:03:02 -0400309 // The next draw picture will notice that fNextDrawPictureToLayerID is set and
310 // redirect the picture to the offscreen layer.
Brian Salomon06c9e292021-04-29 14:10:23 -0400311 return;
312 } else if (tokens[0].equals(kSurfaceID)) {
313 // Indicates that the following drawImageRect should draw an offscreen layer
314 // to this layer.
315 fNextDrawImageFromLayerID = std::stoi(tokens[1].c_str());
316 return;
317 }
318 }
319 }
320
321 void onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) override {
322 fRecorder.getRecordingCanvas()->private_draw_shadow_rec(path, rec);
323 }
324
325 void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
326 fRecorder.getRecordingCanvas()->drawDrawable(drawable, matrix);
327 }
328
329 void onDrawPicture(const SkPicture* picture,
330 const SkMatrix* matrix,
331 const SkPaint* paint) override {
Brian Salomon33ec61132021-05-12 12:03:02 -0400332 if (fNextDrawPictureToLayerID != -1) {
Brian Salomon06c9e292021-04-29 14:10:23 -0400333 SkASSERT(!matrix);
334 SkASSERT(!paint);
Brian Osman68556bc2021-07-30 15:24:22 -0400335 LayerCmds* layer = &fOffscreenLayers->at(fNextDrawPictureToLayerID);
Brian Salomon33ec61132021-05-12 12:03:02 -0400336 CmdRecordCanvas sc(layer, fOffscreenLayers, &fNextDrawPictureToLayerClipRect);
Brian Salomon06c9e292021-04-29 14:10:23 -0400337 picture->playback(&sc);
Brian Salomon33ec61132021-05-12 12:03:02 -0400338 fNextDrawPictureToLayerID = -1;
339 fNextDrawPictureToLayerClipRect = SkIRect::MakeEmpty();
Brian Salomon06c9e292021-04-29 14:10:23 -0400340 return;
341 }
342 if (paint) {
343 this->saveLayer(nullptr, paint);
344 }
345 if (matrix) {
346 this->save();
347 this->concat(*matrix);
348 }
349
350 picture->playback(this);
351
352 if (matrix) {
353 this->restore();
354 }
355 if (paint) {
356 this->restore();
357 }
358 fRecorder.getRecordingCanvas()->drawPicture(picture, matrix, paint);
359 }
360
361private:
362 void recordPicCmd() {
363 auto cmd = std::make_unique<PicCmd>();
364 cmd->fContent = fRecorder.finishRecordingAsPicture();
Brian Salomon33ec61132021-05-12 12:03:02 -0400365 cmd->fClipRect = fClipRect;
Brian Salomon06c9e292021-04-29 14:10:23 -0400366 if (cmd->fContent) {
367 fDst->fCmds.push_back(std::move(cmd));
368 }
369 // Set up to accumulate again.
370 fRecorder.beginRecording(SkRect::Make(fDst->fDimensions));
371 }
372
373 SkPictureRecorder fRecorder; // accumulates draws until we draw an offscreen into this layer.
Brian Osman68556bc2021-07-30 15:24:22 -0400374 LayerCmds* fDst = nullptr;
Brian Salomon33ec61132021-05-12 12:03:02 -0400375 SkIRect fClipRect = SkIRect::MakeEmpty();
376 int fNextDrawPictureToLayerID = -1;
377 SkIRect fNextDrawPictureToLayerClipRect = SkIRect::MakeEmpty();
378 int fNextDrawImageFromLayerID = -1;
379 LayerMap* fOffscreenLayers = nullptr;
Brian Salomon06c9e292021-04-29 14:10:23 -0400380};
381
382///////////////////////////////////////////////////////////////////////////////
383
384std::unique_ptr<MSKPPlayer> MSKPPlayer::Make(SkStreamSeekable* stream) {
385 auto deserialContext = std::make_unique<SkSharingDeserialContext>();
386 SkDeserialProcs procs;
387 procs.fImageProc = SkSharingDeserialContext::deserializeImage;
388 procs.fImageCtx = deserialContext.get();
389
390 int pageCount = SkMultiPictureDocumentReadPageCount(stream);
391 if (!pageCount) {
392 return nullptr;
393 }
394 std::vector<SkDocumentPage> pages(pageCount);
395 if (!SkMultiPictureDocumentRead(stream, pages.data(), pageCount, &procs)) {
396 return nullptr;
397 }
398 std::unique_ptr<MSKPPlayer> result(new MSKPPlayer);
399 result->fRootLayers.reserve(pages.size());
400 for (const auto& page : pages) {
401 SkISize dims = {SkScalarCeilToInt(page.fSize.width()),
402 SkScalarCeilToInt(page.fSize.height())};
403 result->fRootLayers.emplace_back();
404 result->fRootLayers.back().fDimensions = dims;
405 result->fMaxDimensions.fWidth = std::max(dims.width() , result->fMaxDimensions.width() );
406 result->fMaxDimensions.fHeight = std::max(dims.height(), result->fMaxDimensions.height());
407 CmdRecordCanvas sc(&result->fRootLayers.back(), &result->fOffscreenLayers);
408 page.fPicture->playback(&sc);
409 }
410 return result;
411}
412
413MSKPPlayer::~MSKPPlayer() = default;
414
415SkISize MSKPPlayer::frameDimensions(int i) const {
416 if (i < 0 || i >= this->numFrames()) {
417 return {-1, -1};
418 }
419 return fRootLayers[i].fDimensions;
420}
421
422bool MSKPPlayer::playFrame(SkCanvas* canvas, int i) {
423 if (i < 0 || i >= this->numFrames()) {
424 return false;
425 }
426
427 // Find the first offscreen layer that has a valid surface. If it's recording context
428 // differs from the passed canvas's then reset all the layers. Playback will
429 // automatically allocate new surfaces for offscreen layers as they're encountered.
430 for (const auto& ols : fOffscreenLayerStates) {
431 const LayerState& state = ols.second;
432 if (state.fSurface) {
433 if (state.fSurface->recordingContext() != canvas->recordingContext()) {
434 this->resetLayers();
435 }
436 break;
437 }
438 }
439
440 // Replay all the commands for this frame to the caller's canvas.
Brian Osman68556bc2021-07-30 15:24:22 -0400441 const LayerCmds& layer = fRootLayers[i];
Brian Salomon06c9e292021-04-29 14:10:23 -0400442 for (const auto& cmd : layer.fCmds) {
443 cmd->draw(canvas, fOffscreenLayers, &fOffscreenLayerStates);
444 }
445 return true;
446}
447
Brian Osman68556bc2021-07-30 15:24:22 -0400448sk_sp<SkSurface> MSKPPlayer::MakeSurfaceForLayer(const LayerCmds& layer, SkCanvas* rootCanvas) {
Brian Salomon31fddc32021-04-30 13:08:55 -0400449 // Assume layer has same surface props and info as this (mskp doesn't currently record this
450 // data).
451 SkSurfaceProps props;
452 rootCanvas->getProps(&props);
453 return rootCanvas->makeSurface(rootCanvas->imageInfo().makeDimensions(layer.fDimensions),
454 &props);
455}
456
Brian Salomon06c9e292021-04-29 14:10:23 -0400457void MSKPPlayer::resetLayers() { fOffscreenLayerStates.clear(); }
Brian Salomon31fddc32021-04-30 13:08:55 -0400458
459void MSKPPlayer::rewindLayers() {
460 for (auto& [id, state] : fOffscreenLayerStates) {
461 state.fCurrCmd = -1;
462 }
463}
464
465void MSKPPlayer::allocateLayers(SkCanvas* canvas) {
466 // Iterate over layers not states as states are lazily created in playback but here we want to
467 // create any that don't already exist.
468 for (auto& [id, layer] : fOffscreenLayers) {
469 LayerState& state = fOffscreenLayerStates[id];
470 if (!state.fSurface || state.fSurface->recordingContext() != canvas->recordingContext()) {
471 state.fCurrCmd = -1;
472 state.fSurface = MakeSurfaceForLayer(fOffscreenLayers[id], canvas);
473 }
474 }
475}
Brian Salomon33ec61132021-05-12 12:03:02 -0400476
477std::vector<int> MSKPPlayer::layerIDs(int frame) const {
478 std::vector<int> result;
479 if (frame < 0) {
480 result.reserve(fOffscreenLayers.size());
481 for (auto& [id, _] : fOffscreenLayers) {
482 result.push_back(id);
483 }
484 return result;
485 }
486 if (frame < static_cast<int>(fRootLayers.size())) {
487 this->collectReferencedLayers(fRootLayers[frame], &result);
488 }
489 return result;
490}
491
492sk_sp<SkImage> MSKPPlayer::layerSnapshot(int layerID) const {
493 auto iter = fOffscreenLayerStates.find(layerID);
494 if (iter == fOffscreenLayerStates.end() || !iter->second.fSurface) {
495 return nullptr;
496 }
497 return iter->second.fSurface->makeImageSnapshot();
498}
499
Brian Osman68556bc2021-07-30 15:24:22 -0400500void MSKPPlayer::collectReferencedLayers(const LayerCmds& layer, std::vector<int>* out) const {
Brian Salomon33ec61132021-05-12 12:03:02 -0400501 for (const auto& cmd : layer.fCmds) {
502 if (int id = cmd->layerID(); id >= 0) {
503 // Linear, but we'd need to have a lot of layers to actually care.
504 if (std::find(out->begin(), out->end(), id) == out->end()) {
505 out->push_back(id);
506 auto iter = fOffscreenLayers.find(id);
507 SkASSERT(iter != fOffscreenLayers.end());
508 this->collectReferencedLayers(iter->second, out);
509 }
510 }
511 }
512}