xref: /aosp_15_r20/external/skia/tools/debugger/DebugLayerManager.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2019 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "tools/debugger/DebugLayerManager.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkAlphaType.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorSpace.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColorType.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "tools/debugger/DebugCanvas.h"
22*c8dee2aaSAndroid Build Coastguard Worker 
23*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
24*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
25*c8dee2aaSAndroid Build Coastguard Worker #include <unordered_map>
26*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
27*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
28*c8dee2aaSAndroid Build Coastguard Worker 
setCommand(int nodeId,int frame,int command)29*c8dee2aaSAndroid Build Coastguard Worker void DebugLayerManager::setCommand(int nodeId, int frame, int command) {
30*c8dee2aaSAndroid Build Coastguard Worker     auto* drawEvent = fDraws.find({frame, nodeId});
31*c8dee2aaSAndroid Build Coastguard Worker     if (!drawEvent) {
32*c8dee2aaSAndroid Build Coastguard Worker         SkDebugf(
33*c8dee2aaSAndroid Build Coastguard Worker                 "Could not set command playhead for event {%d, %d}, it is not tracked by"
34*c8dee2aaSAndroid Build Coastguard Worker                 "DebugLayerManager.\n",
35*c8dee2aaSAndroid Build Coastguard Worker                 frame,
36*c8dee2aaSAndroid Build Coastguard Worker                 nodeId);
37*c8dee2aaSAndroid Build Coastguard Worker         return;
38*c8dee2aaSAndroid Build Coastguard Worker     }
39*c8dee2aaSAndroid Build Coastguard Worker     const int count = drawEvent->debugCanvas->getSize();
40*c8dee2aaSAndroid Build Coastguard Worker     drawEvent->command = command < count ? command : count - 1;
41*c8dee2aaSAndroid Build Coastguard Worker     // Invalidate stored images that depended on this combination of node and frame.
42*c8dee2aaSAndroid Build Coastguard Worker     // actually this does all of the events for this nodeId, but close enough.
43*c8dee2aaSAndroid Build Coastguard Worker     auto relevantFrames = listFramesForNode(nodeId);
44*c8dee2aaSAndroid Build Coastguard Worker     for (const auto& f : relevantFrames) {
45*c8dee2aaSAndroid Build Coastguard Worker         fDraws[{f, nodeId}].image = nullptr;
46*c8dee2aaSAndroid Build Coastguard Worker     }
47*c8dee2aaSAndroid Build Coastguard Worker }
48*c8dee2aaSAndroid Build Coastguard Worker 
storeSkPicture(int nodeId,int frame,const sk_sp<SkPicture> & picture,SkIRect dirty)49*c8dee2aaSAndroid Build Coastguard Worker void DebugLayerManager::storeSkPicture(int nodeId,
50*c8dee2aaSAndroid Build Coastguard Worker                                        int frame,
51*c8dee2aaSAndroid Build Coastguard Worker                                        const sk_sp<SkPicture>& picture,
52*c8dee2aaSAndroid Build Coastguard Worker                                        SkIRect dirty) {
53*c8dee2aaSAndroid Build Coastguard Worker     const LayerKey k = {frame, nodeId};
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker     // Make debug canvas using bounds from SkPicture. This will be equal to whatever width and
56*c8dee2aaSAndroid Build Coastguard Worker     // height were passed into SkPictureRecorder::beginRecording(w, h) which is the layer bounds.
57*c8dee2aaSAndroid Build Coastguard Worker     const auto& layerBounds = picture->cullRect().roundOut();
58*c8dee2aaSAndroid Build Coastguard Worker     auto debugCanvas = std::make_unique<DebugCanvas>(layerBounds);
59*c8dee2aaSAndroid Build Coastguard Worker     // Must be set or they end up undefined due to cosmic rays, bad luck, etc.
60*c8dee2aaSAndroid Build Coastguard Worker     debugCanvas->setOverdrawViz(false);
61*c8dee2aaSAndroid Build Coastguard Worker     debugCanvas->setDrawGpuOpBounds(false);
62*c8dee2aaSAndroid Build Coastguard Worker     debugCanvas->setClipVizColor(SK_ColorTRANSPARENT);
63*c8dee2aaSAndroid Build Coastguard Worker     // Setting this allows a layer to contain another layer. TODO(nifong): write a test for this.
64*c8dee2aaSAndroid Build Coastguard Worker     debugCanvas->setLayerManagerAndFrame(this, frame);
65*c8dee2aaSAndroid Build Coastguard Worker     // Only draw picture to the debug canvas once.
66*c8dee2aaSAndroid Build Coastguard Worker     debugCanvas->drawPicture(picture);
67*c8dee2aaSAndroid Build Coastguard Worker     int numCommands = debugCanvas->getSize();
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker     DrawEvent event = {
70*c8dee2aaSAndroid Build Coastguard Worker             frame == 0 || dirty == layerBounds,           // fullRedraw
71*c8dee2aaSAndroid Build Coastguard Worker             nullptr,                                      // image
72*c8dee2aaSAndroid Build Coastguard Worker             std::move(debugCanvas),                       // debugCanvas
73*c8dee2aaSAndroid Build Coastguard Worker             numCommands - 1,                              // command
74*c8dee2aaSAndroid Build Coastguard Worker             {layerBounds.width(), layerBounds.height()},  // layerBounds
75*c8dee2aaSAndroid Build Coastguard Worker     };
76*c8dee2aaSAndroid Build Coastguard Worker 
77*c8dee2aaSAndroid Build Coastguard Worker     fDraws.set(k, std::move(event));
78*c8dee2aaSAndroid Build Coastguard Worker     keys.push_back(k);
79*c8dee2aaSAndroid Build Coastguard Worker }
80*c8dee2aaSAndroid Build Coastguard Worker 
drawLayerEventTo(SkSurface * surface,const int nodeId,const int frame)81*c8dee2aaSAndroid Build Coastguard Worker void DebugLayerManager::drawLayerEventTo(SkSurface* surface, const int nodeId, const int frame) {
82*c8dee2aaSAndroid Build Coastguard Worker     auto& evt = fDraws[{frame, nodeId}];
83*c8dee2aaSAndroid Build Coastguard Worker     evt.debugCanvas->drawTo(surface->getCanvas(), evt.command);
84*c8dee2aaSAndroid Build Coastguard Worker }
85*c8dee2aaSAndroid Build Coastguard Worker 
getLayerAsImage(const int nodeId,const int frame)86*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> DebugLayerManager::getLayerAsImage(const int nodeId, const int frame) {
87*c8dee2aaSAndroid Build Coastguard Worker   // What is the last frame having an SkPicture for this layer? call it frame N
88*c8dee2aaSAndroid Build Coastguard Worker   // have cached image of it? if so, return it.
89*c8dee2aaSAndroid Build Coastguard Worker   // if not, draw it at frame N by the following method:
90*c8dee2aaSAndroid Build Coastguard Worker   // The picture at frame N could have been a full redraw, or it could have been clipped to a
91*c8dee2aaSAndroid Build Coastguard Worker   // dirty region. In order to know what the layer looked like on this frame, we must draw every
92*c8dee2aaSAndroid Build Coastguard Worker   // picture starting with the last full redraw, up to the last one before the current frame, since
93*c8dee2aaSAndroid Build Coastguard Worker   // any of those previous draws could be showing through.
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker   // list of frames this node was updated on.
96*c8dee2aaSAndroid Build Coastguard Worker   auto relevantFrames = listFramesForNode(nodeId);
97*c8dee2aaSAndroid Build Coastguard Worker   // find largest one not greater than `frame`.
98*c8dee2aaSAndroid Build Coastguard Worker   uint32_t i = relevantFrames.size()-1;
99*c8dee2aaSAndroid Build Coastguard Worker   while (relevantFrames[i] > frame) { i--; }
100*c8dee2aaSAndroid Build Coastguard Worker   const int frameN = relevantFrames[i];
101*c8dee2aaSAndroid Build Coastguard Worker   // Fetch the draw event
102*c8dee2aaSAndroid Build Coastguard Worker   auto& drawEvent = fDraws[{frameN, nodeId}];
103*c8dee2aaSAndroid Build Coastguard Worker   // if an image of this is cached, return it.
104*c8dee2aaSAndroid Build Coastguard Worker   if (drawEvent.image) {
105*c8dee2aaSAndroid Build Coastguard Worker     return drawEvent.image;
106*c8dee2aaSAndroid Build Coastguard Worker   }
107*c8dee2aaSAndroid Build Coastguard Worker   // when it's not cached, we'll have to render it in an offscreen surface.
108*c8dee2aaSAndroid Build Coastguard Worker   // start at the last full redraw. (pick up counting backwards from above)
109*c8dee2aaSAndroid Build Coastguard Worker   while (i>0 && !(fDraws[{relevantFrames[i], nodeId}].fullRedraw)) { i--; }
110*c8dee2aaSAndroid Build Coastguard Worker   // The correct layer bounds can be obtained from any drawEvent on this layer.
111*c8dee2aaSAndroid Build Coastguard Worker   // the color type and alpha type are chosen here to match wasm-skp-debugger/cpu.js which was
112*c8dee2aaSAndroid Build Coastguard Worker   // chosen to match the capabilities of HTML canvas, which this ultimately has to be drawn into.
113*c8dee2aaSAndroid Build Coastguard Worker   // TODO(nifong): introduce a method of letting the user choose the backend for this.
114*c8dee2aaSAndroid Build Coastguard Worker   auto surface = SkSurfaces::Raster(SkImageInfo::Make(
115*c8dee2aaSAndroid Build Coastguard Worker           drawEvent.layerBounds, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, nullptr));
116*c8dee2aaSAndroid Build Coastguard Worker   // draw everything from the last full redraw up to the current frame.
117*c8dee2aaSAndroid Build Coastguard Worker   // other frames drawn are partial, meaning they were clipped to not completely cover the layer.
118*c8dee2aaSAndroid Build Coastguard Worker   // count back up with i
119*c8dee2aaSAndroid Build Coastguard Worker   for (; i<relevantFrames.size() && relevantFrames[i]<=frameN; i++) {
120*c8dee2aaSAndroid Build Coastguard Worker     drawLayerEventTo(surface.get(), nodeId, relevantFrames[i]);
121*c8dee2aaSAndroid Build Coastguard Worker   }
122*c8dee2aaSAndroid Build Coastguard Worker   drawEvent.image = surface->makeImageSnapshot();
123*c8dee2aaSAndroid Build Coastguard Worker   return drawEvent.image;
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker 
event(int nodeId,int frame) const126*c8dee2aaSAndroid Build Coastguard Worker DebugLayerManager::DrawEventSummary DebugLayerManager::event(int nodeId, int frame) const {
127*c8dee2aaSAndroid Build Coastguard Worker   auto* evt = fDraws.find({frame, nodeId});
128*c8dee2aaSAndroid Build Coastguard Worker   if (!evt) { return {}; }
129*c8dee2aaSAndroid Build Coastguard Worker   return {
130*c8dee2aaSAndroid Build Coastguard Worker     true, evt->debugCanvas->getSize(),
131*c8dee2aaSAndroid Build Coastguard Worker     evt->layerBounds.width(), evt->layerBounds.height()
132*c8dee2aaSAndroid Build Coastguard Worker   };
133*c8dee2aaSAndroid Build Coastguard Worker }
134*c8dee2aaSAndroid Build Coastguard Worker 
summarizeLayers(int frame) const135*c8dee2aaSAndroid Build Coastguard Worker std::vector<DebugLayerManager::LayerSummary> DebugLayerManager::summarizeLayers(int frame) const {
136*c8dee2aaSAndroid Build Coastguard Worker   // Find the last update on or before `frame` for every node
137*c8dee2aaSAndroid Build Coastguard Worker   // key: nodeId, one entry for every layer
138*c8dee2aaSAndroid Build Coastguard Worker   // value: summary of the layer.
139*c8dee2aaSAndroid Build Coastguard Worker   std::unordered_map<int, LayerSummary> summaryMap;
140*c8dee2aaSAndroid Build Coastguard Worker   for (const auto& key : keys) {
141*c8dee2aaSAndroid Build Coastguard Worker     auto* evt = fDraws.find(key);
142*c8dee2aaSAndroid Build Coastguard Worker     if (!evt) { continue; }
143*c8dee2aaSAndroid Build Coastguard Worker     // -1 as a default value for the last update serves as a way of indicating that this layer
144*c8dee2aaSAndroid Build Coastguard Worker     // is present in the animation, but doesn't have an update less than or equal to `frame`
145*c8dee2aaSAndroid Build Coastguard Worker     int lastUpdate = (key.frame <= frame ? key.frame : -1);
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker     // do we have an entry for this layer yet? is it later than the one we're looking at?
148*c8dee2aaSAndroid Build Coastguard Worker     auto found = summaryMap.find(key.nodeId);
149*c8dee2aaSAndroid Build Coastguard Worker     if (found != summaryMap.end()) {
150*c8dee2aaSAndroid Build Coastguard Worker       LayerSummary& item = summaryMap[key.nodeId];
151*c8dee2aaSAndroid Build Coastguard Worker       if (lastUpdate > item.frameOfLastUpdate) {
152*c8dee2aaSAndroid Build Coastguard Worker         item.frameOfLastUpdate = key.frame;
153*c8dee2aaSAndroid Build Coastguard Worker         item.fullRedraw = evt->fullRedraw;
154*c8dee2aaSAndroid Build Coastguard Worker       }
155*c8dee2aaSAndroid Build Coastguard Worker     } else {
156*c8dee2aaSAndroid Build Coastguard Worker       // record first entry for this layer
157*c8dee2aaSAndroid Build Coastguard Worker       summaryMap.insert({key.nodeId, {
158*c8dee2aaSAndroid Build Coastguard Worker         key.nodeId, lastUpdate, evt->fullRedraw,
159*c8dee2aaSAndroid Build Coastguard Worker         evt->layerBounds.width(), evt->layerBounds.height()
160*c8dee2aaSAndroid Build Coastguard Worker       }});
161*c8dee2aaSAndroid Build Coastguard Worker     }
162*c8dee2aaSAndroid Build Coastguard Worker   }
163*c8dee2aaSAndroid Build Coastguard Worker   std::vector<LayerSummary> result;
164*c8dee2aaSAndroid Build Coastguard Worker   for (auto it = summaryMap.begin(); it != summaryMap.end(); ++it) {
165*c8dee2aaSAndroid Build Coastguard Worker     result.push_back(it->second);
166*c8dee2aaSAndroid Build Coastguard Worker   }
167*c8dee2aaSAndroid Build Coastguard Worker   return result;
168*c8dee2aaSAndroid Build Coastguard Worker }
169*c8dee2aaSAndroid Build Coastguard Worker 
listNodesForFrame(int frame) const170*c8dee2aaSAndroid Build Coastguard Worker std::vector<int> DebugLayerManager::listNodesForFrame(int frame) const {
171*c8dee2aaSAndroid Build Coastguard Worker   std::vector<int> result;
172*c8dee2aaSAndroid Build Coastguard Worker   for (const auto& key : keys) {
173*c8dee2aaSAndroid Build Coastguard Worker     if (key.frame == frame) {
174*c8dee2aaSAndroid Build Coastguard Worker       result.push_back(key.nodeId);
175*c8dee2aaSAndroid Build Coastguard Worker     }
176*c8dee2aaSAndroid Build Coastguard Worker   }
177*c8dee2aaSAndroid Build Coastguard Worker   return result;
178*c8dee2aaSAndroid Build Coastguard Worker }
179*c8dee2aaSAndroid Build Coastguard Worker 
listFramesForNode(int nodeId) const180*c8dee2aaSAndroid Build Coastguard Worker std::vector<int> DebugLayerManager::listFramesForNode(int nodeId) const {
181*c8dee2aaSAndroid Build Coastguard Worker   std::vector<int> result;
182*c8dee2aaSAndroid Build Coastguard Worker   for (const auto& key : keys) {
183*c8dee2aaSAndroid Build Coastguard Worker     if (key.nodeId == nodeId) {
184*c8dee2aaSAndroid Build Coastguard Worker       result.push_back(key.frame);
185*c8dee2aaSAndroid Build Coastguard Worker     }
186*c8dee2aaSAndroid Build Coastguard Worker   }
187*c8dee2aaSAndroid Build Coastguard Worker   return result;
188*c8dee2aaSAndroid Build Coastguard Worker }
189*c8dee2aaSAndroid Build Coastguard Worker 
getEventDebugCanvas(int nodeId,int frame)190*c8dee2aaSAndroid Build Coastguard Worker DebugCanvas* DebugLayerManager::getEventDebugCanvas(int nodeId, int frame) {
191*c8dee2aaSAndroid Build Coastguard Worker   auto& evt = fDraws[{frame, nodeId}];
192*c8dee2aaSAndroid Build Coastguard Worker   return evt.debugCanvas.get();
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker 
setOverdrawViz(bool overdrawViz)195*c8dee2aaSAndroid Build Coastguard Worker void DebugLayerManager::setOverdrawViz(bool overdrawViz) {
196*c8dee2aaSAndroid Build Coastguard Worker   for (const auto& key : keys) {
197*c8dee2aaSAndroid Build Coastguard Worker     auto& evt = fDraws[key];
198*c8dee2aaSAndroid Build Coastguard Worker     evt.debugCanvas->setOverdrawViz(overdrawViz);
199*c8dee2aaSAndroid Build Coastguard Worker   }
200*c8dee2aaSAndroid Build Coastguard Worker }
201*c8dee2aaSAndroid Build Coastguard Worker 
setClipVizColor(SkColor clipVizColor)202*c8dee2aaSAndroid Build Coastguard Worker void DebugLayerManager::setClipVizColor(SkColor clipVizColor) {
203*c8dee2aaSAndroid Build Coastguard Worker   for (const auto& key : keys) {
204*c8dee2aaSAndroid Build Coastguard Worker     auto& evt = fDraws[key];
205*c8dee2aaSAndroid Build Coastguard Worker     evt.debugCanvas->setClipVizColor(clipVizColor);
206*c8dee2aaSAndroid Build Coastguard Worker   }
207*c8dee2aaSAndroid Build Coastguard Worker }
208*c8dee2aaSAndroid Build Coastguard Worker 
setDrawGpuOpBounds(bool drawGpuOpBounds)209*c8dee2aaSAndroid Build Coastguard Worker void DebugLayerManager::setDrawGpuOpBounds(bool drawGpuOpBounds) {
210*c8dee2aaSAndroid Build Coastguard Worker   for (const auto& key : keys) {
211*c8dee2aaSAndroid Build Coastguard Worker     auto& evt = fDraws[key];
212*c8dee2aaSAndroid Build Coastguard Worker     evt.debugCanvas->setDrawGpuOpBounds(drawGpuOpBounds);
213*c8dee2aaSAndroid Build Coastguard Worker   }
214*c8dee2aaSAndroid Build Coastguard Worker }
215