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