1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#ifndef DEBUGLAYERMANAGER_H_
9cb93a386Sopenharmony_ci#define DEBUGLAYERMANAGER_H_
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ci#include "include/core/SkImage.h"
12cb93a386Sopenharmony_ci#include "include/private/SkTHash.h"
13cb93a386Sopenharmony_ci#include "src/utils/SkJSONWriter.h"
14cb93a386Sopenharmony_ci#include "tools/debugger/DebugCanvas.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ci#include <vector>
17cb93a386Sopenharmony_ci
18cb93a386Sopenharmony_ci// A class to assist in playing back and debugging an mskp file containing offscreen layer commands.
19cb93a386Sopenharmony_ci
20cb93a386Sopenharmony_ci// Holds SkPictures necessary to draw layers in one or more DebugCanvases. During
21cb93a386Sopenharmony_ci// recording of the mskp file on Android, each layer had a RenderNode id, which is recorded with
22cb93a386Sopenharmony_ci// the layer's draw commands.
23cb93a386Sopenharmony_ci// Creates one surface (cpu only for now) for each layer, and renders
24cb93a386Sopenharmony_ci// pictures to it up to the requested command using a DebugCanvas.
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci// Animations are expected to, but may not always use a layer on more than frame.
27cb93a386Sopenharmony_ci// the layer may be drawn to more than once, and each different draw is saved for reconstructing the
28cb93a386Sopenharmony_ci// layer as it was on any frame. Draws may be partial, meaning their commands were clipped to not
29cb93a386Sopenharmony_ci// cover the entire layer.
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci// Clients may ask for a rendering of a given layer by its RenderNode id and frame, and
32cb93a386Sopenharmony_ci// this class will return a rendering of how it looked on that frame.
33cb93a386Sopenharmony_ci// returning an SkImage snapshot of the internally managed surface.
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ciclass DebugCanvas;
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_ciclass DebugLayerManager {
38cb93a386Sopenharmony_cipublic:
39cb93a386Sopenharmony_ci    DebugLayerManager() {}
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ci    // Store an SkPicture under a given nodeId (and under the currently set frame number)
42cb93a386Sopenharmony_ci    // `dirty` is the recorded rect that was used to call androidFramework_setDeviceClipRestriction
43cb93a386Sopenharmony_ci    // when the layer was drawn.
44cb93a386Sopenharmony_ci    void storeSkPicture(int nodeId, int frame, sk_sp<SkPicture> picture, SkIRect dirty);
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_ci    // Set's the command playback head for a given picture/draw event.
47cb93a386Sopenharmony_ci    void setCommand(int nodeId, int frame, int command);
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci    void drawLayerEventTo(SkSurface*, const int nodeId, const int frame);
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ci    // getLayerAsImage draws the given layer as it would have looked on frame and returns an image.
52cb93a386Sopenharmony_ci    // Though each picture can be played back in as many ways as there are commands, we will let
53cb93a386Sopenharmony_ci    // that be determined by the user who sets an independent playhead for each draw event, tracked
54cb93a386Sopenharmony_ci    // here, so it stays how they left it.
55cb93a386Sopenharmony_ci    // For example: Say we are drawing a layer at frame 10.
56cb93a386Sopenharmony_ci    // Frame 0:  Layer was completely redrawn. By default we draw it to its last command. We always
57cb93a386Sopenharmony_ci    //           save the result by (nodeId, frame)
58cb93a386Sopenharmony_ci    // Frame 5:  Layer was partially redrawn, and the user has inspected this draw event, leaving
59cb93a386Sopenharmony_ci    //           its command playhead at command 50/100. We have drew this at the time and save how
60cb93a386Sopenharmony_ci    //           the result looked (all of the commands at frame 0, then half of the commands in the
61cb93a386Sopenharmony_ci    //           partial draw at frame 5)
62cb93a386Sopenharmony_ci    // Frame 10: Another partial redraw, un-altered, drawn on top of the result from frame 5. We
63cb93a386Sopenharmony_ci    //           return this as the image of how the layer should look on frame 10
64cb93a386Sopenharmony_ci    // Frame 15: A full redraw
65cb93a386Sopenharmony_ci    //
66cb93a386Sopenharmony_ci    // If the user then comes along and moves the command playhead of the picture at frame 0,
67cb93a386Sopenharmony_ci    // we invalidate the stored images for 0, 5, and 10, but we can leave 15 alone if we have it.
68cb93a386Sopenharmony_ci    //
69cb93a386Sopenharmony_ci    // Which leaves us with one less degree of freedom to think about when implementing this
70cb93a386Sopenharmony_ci    // function: We can assume there is only one way to play back a given picture. :)
71cb93a386Sopenharmony_ci    //
72cb93a386Sopenharmony_ci    // The reason the public version of this function doesn't let you specify the frame, is that
73cb93a386Sopenharmony_ci    // I expect DebugCanvas to call it, which doesn't know which frame it's rendering. The code in
74cb93a386Sopenharmony_ci    // debugger_bindings.cpp does know, which it why I'm having it set the frame via setFrame(int)
75cb93a386Sopenharmony_ci    sk_sp<SkImage> getLayerAsImage(const int nodeId, const int frame);
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci    // Flat because it's meant to be bindable by emscripten and returned to the javascript side
78cb93a386Sopenharmony_ci    struct DrawEventSummary {
79cb93a386Sopenharmony_ci        // true when the drawEvent represents a valid result.
80cb93a386Sopenharmony_ci        bool found = false;
81cb93a386Sopenharmony_ci        int commandCount;
82cb93a386Sopenharmony_ci        int layerWidth;
83cb93a386Sopenharmony_ci        int layerHeight;
84cb93a386Sopenharmony_ci    };
85cb93a386Sopenharmony_ci    // return the summary of a single event
86cb93a386Sopenharmony_ci    DrawEventSummary event(int nodeId, int frame) const;
87cb93a386Sopenharmony_ci
88cb93a386Sopenharmony_ci    struct LayerSummary {
89cb93a386Sopenharmony_ci        int nodeId;
90cb93a386Sopenharmony_ci        // Last frame less than or equal to the given frame which has an update for this layer
91cb93a386Sopenharmony_ci        // -1 if the layer has no updates satisfying that constraint.
92cb93a386Sopenharmony_ci        int frameOfLastUpdate;
93cb93a386Sopenharmony_ci        // Whether the last update was a full redraw.
94cb93a386Sopenharmony_ci        bool fullRedraw;
95cb93a386Sopenharmony_ci        int layerWidth;
96cb93a386Sopenharmony_ci        int layerHeight;
97cb93a386Sopenharmony_ci    };
98cb93a386Sopenharmony_ci    // Return a list summarizing all layers, with info relevant to the current frame.
99cb93a386Sopenharmony_ci    std::vector<LayerSummary> summarizeLayers(int frame) const;
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ci    // Return the list of node ids which have DrawEvents on the given frame
102cb93a386Sopenharmony_ci    std::vector<int> listNodesForFrame(int frame) const;
103cb93a386Sopenharmony_ci    // Return the list of frames on which the given node had DrawEvents.
104cb93a386Sopenharmony_ci    std::vector<int> listFramesForNode(int nodeId) const;
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    // asks the DebugCanvas of the indicated draw event to serialize it's commands as JSON.
107cb93a386Sopenharmony_ci    void toJSON(SkJSONWriter&, UrlDataManager&, SkCanvas*, int nodeId, int frame);
108cb93a386Sopenharmony_ci
109cb93a386Sopenharmony_ci    // return a pointer to the debugcanvas of a given draw event.
110cb93a386Sopenharmony_ci    DebugCanvas* getEventDebugCanvas(int nodeid, int frame);
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    // forwards the provided setting to all debugcanvases.
113cb93a386Sopenharmony_ci    void setOverdrawViz(bool overdrawViz);
114cb93a386Sopenharmony_ci    void setClipVizColor(SkColor clipVizColor);
115cb93a386Sopenharmony_ci    void setDrawGpuOpBounds(bool drawGpuOpBounds);
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    struct LayerKey{
118cb93a386Sopenharmony_ci        int frame; // frame of animation on which this event was recorded.
119cb93a386Sopenharmony_ci        int nodeId; // the render node id of the layer which was drawn to.
120cb93a386Sopenharmony_ci
121cb93a386Sopenharmony_ci        bool operator==(const LayerKey& b) const {
122cb93a386Sopenharmony_ci            return this->frame==b.frame && this->nodeId==b.nodeId;
123cb93a386Sopenharmony_ci        }
124cb93a386Sopenharmony_ci    };
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    // return list of keys that identify layer update events
127cb93a386Sopenharmony_ci    const std::vector<DebugLayerManager::LayerKey>& getKeys() const { return keys; }
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ciprivate:
130cb93a386Sopenharmony_ci    // This class is basically a map from (frame, node) to draw-event
131cb93a386Sopenharmony_ci    // during recording, at the beginning of any frame, one or more layers could have been drawn on.
132cb93a386Sopenharmony_ci    // every draw event was recorded, and when reading the mskp file they are stored and organized
133cb93a386Sopenharmony_ci    // here.
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    struct DrawEvent {
136cb93a386Sopenharmony_ci        // true the pic's clip equals the layer bounds.
137cb93a386Sopenharmony_ci        bool fullRedraw;
138cb93a386Sopenharmony_ci        // the saved result of how the layer looks on this frame.
139cb93a386Sopenharmony_ci        // null if we don't have it.
140cb93a386Sopenharmony_ci        sk_sp<SkImage> image;
141cb93a386Sopenharmony_ci        // A debug canvas used for drawing this picture.
142cb93a386Sopenharmony_ci        // the SkPicture itself isn't saved, since it's in the DebugCanvas.
143cb93a386Sopenharmony_ci        std::unique_ptr<DebugCanvas> debugCanvas;
144cb93a386Sopenharmony_ci        // the command index where the debugCanvas was left off.
145cb93a386Sopenharmony_ci        int command;
146cb93a386Sopenharmony_ci        // the size of the layer this drew into. redundant between multiple DrawEvents on the same
147cb93a386Sopenharmony_ci        // layer but helpful.
148cb93a386Sopenharmony_ci        SkISize layerBounds;
149cb93a386Sopenharmony_ci    };
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci    SkTHashMap<LayerKey, DrawEvent> fDraws;
152cb93a386Sopenharmony_ci    // The list of all keys in the map above (it has no keys() method)
153cb93a386Sopenharmony_ci    std::vector<LayerKey> keys;
154cb93a386Sopenharmony_ci};
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_ci#endif
157