xref: /aosp_15_r20/external/skia/src/gpu/ganesh/GrAuditTrail.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2016 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 "src/gpu/ganesh/GrAuditTrail.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
12*c8dee2aaSAndroid Build Coastguard Worker 
13*c8dee2aaSAndroid Build Coastguard Worker const int GrAuditTrail::kGrAuditTrailInvalidID = -1;
14*c8dee2aaSAndroid Build Coastguard Worker 
addOp(const GrOp * op,GrRenderTargetProxy::UniqueID proxyID)15*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::addOp(const GrOp* op, GrRenderTargetProxy::UniqueID proxyID) {
16*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fEnabled);
17*c8dee2aaSAndroid Build Coastguard Worker     Op* auditOp = new Op;
18*c8dee2aaSAndroid Build Coastguard Worker     fOpPool.emplace_back(auditOp);
19*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fName = op->name();
20*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fBounds = op->bounds();
21*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fClientID = kGrAuditTrailInvalidID;
22*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fOpsTaskID = kGrAuditTrailInvalidID;
23*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fChildID = kGrAuditTrailInvalidID;
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker     // consume the current stack trace if any
26*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fStackTrace = fCurrentStackTrace;
27*c8dee2aaSAndroid Build Coastguard Worker     fCurrentStackTrace.clear();
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker     if (fClientID != kGrAuditTrailInvalidID) {
30*c8dee2aaSAndroid Build Coastguard Worker         auditOp->fClientID = fClientID;
31*c8dee2aaSAndroid Build Coastguard Worker         Ops** opsLookup = fClientIDLookup.find(fClientID);
32*c8dee2aaSAndroid Build Coastguard Worker         Ops* ops = nullptr;
33*c8dee2aaSAndroid Build Coastguard Worker         if (!opsLookup) {
34*c8dee2aaSAndroid Build Coastguard Worker             ops = new Ops;
35*c8dee2aaSAndroid Build Coastguard Worker             fClientIDLookup.set(fClientID, ops);
36*c8dee2aaSAndroid Build Coastguard Worker         } else {
37*c8dee2aaSAndroid Build Coastguard Worker             ops = *opsLookup;
38*c8dee2aaSAndroid Build Coastguard Worker         }
39*c8dee2aaSAndroid Build Coastguard Worker 
40*c8dee2aaSAndroid Build Coastguard Worker         ops->push_back(auditOp);
41*c8dee2aaSAndroid Build Coastguard Worker     }
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker     // Our algorithm doesn't bother to reorder inside of an OpNode so the ChildID will start at 0
44*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fOpsTaskID = fOpsTask.size();
45*c8dee2aaSAndroid Build Coastguard Worker     auditOp->fChildID = 0;
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker     // We use the op pointer as a key to find the OpNode we are 'glomming' ops onto
48*c8dee2aaSAndroid Build Coastguard Worker     fIDLookup.set(op->uniqueID(), auditOp->fOpsTaskID);
49*c8dee2aaSAndroid Build Coastguard Worker     OpNode* opNode = new OpNode(proxyID);
50*c8dee2aaSAndroid Build Coastguard Worker     opNode->fBounds = op->bounds();
51*c8dee2aaSAndroid Build Coastguard Worker     opNode->fChildren.push_back(auditOp);
52*c8dee2aaSAndroid Build Coastguard Worker     fOpsTask.emplace_back(opNode);
53*c8dee2aaSAndroid Build Coastguard Worker }
54*c8dee2aaSAndroid Build Coastguard Worker 
opsCombined(const GrOp * consumer,const GrOp * consumed)55*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::opsCombined(const GrOp* consumer, const GrOp* consumed) {
56*c8dee2aaSAndroid Build Coastguard Worker     // Look up the op we are going to glom onto
57*c8dee2aaSAndroid Build Coastguard Worker     int* indexPtr = fIDLookup.find(consumer->uniqueID());
58*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(indexPtr);
59*c8dee2aaSAndroid Build Coastguard Worker     int index = *indexPtr;
60*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(index < fOpsTask.size() && fOpsTask[index]);
61*c8dee2aaSAndroid Build Coastguard Worker     OpNode& consumerOp = *fOpsTask[index];
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker     // Look up the op which will be glommed
64*c8dee2aaSAndroid Build Coastguard Worker     int* consumedPtr = fIDLookup.find(consumed->uniqueID());
65*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(consumedPtr);
66*c8dee2aaSAndroid Build Coastguard Worker     int consumedIndex = *consumedPtr;
67*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(consumedIndex < fOpsTask.size() && fOpsTask[consumedIndex]);
68*c8dee2aaSAndroid Build Coastguard Worker     OpNode& consumedOp = *fOpsTask[consumedIndex];
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker     // steal all of consumed's ops
71*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < consumedOp.fChildren.size(); i++) {
72*c8dee2aaSAndroid Build Coastguard Worker         Op* childOp = consumedOp.fChildren[i];
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker         // set the ids for the child op
75*c8dee2aaSAndroid Build Coastguard Worker         childOp->fOpsTaskID = index;
76*c8dee2aaSAndroid Build Coastguard Worker         childOp->fChildID = consumerOp.fChildren.size();
77*c8dee2aaSAndroid Build Coastguard Worker         consumerOp.fChildren.push_back(childOp);
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker     // Update the bounds for the combineWith node
81*c8dee2aaSAndroid Build Coastguard Worker     consumerOp.fBounds = consumer->bounds();
82*c8dee2aaSAndroid Build Coastguard Worker 
83*c8dee2aaSAndroid Build Coastguard Worker     // remove the old node from our opsTask and clear the combinee's lookup
84*c8dee2aaSAndroid Build Coastguard Worker     // NOTE: because we can't change the shape of the oplist, we use a sentinel
85*c8dee2aaSAndroid Build Coastguard Worker     fOpsTask[consumedIndex].reset(nullptr);
86*c8dee2aaSAndroid Build Coastguard Worker     fIDLookup.remove(consumed->uniqueID());
87*c8dee2aaSAndroid Build Coastguard Worker }
88*c8dee2aaSAndroid Build Coastguard Worker 
copyOutFromOpsTask(OpInfo * outOpInfo,int opsTaskID)89*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::copyOutFromOpsTask(OpInfo* outOpInfo, int opsTaskID) {
90*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(opsTaskID < fOpsTask.size());
91*c8dee2aaSAndroid Build Coastguard Worker     const OpNode* bn = fOpsTask[opsTaskID].get();
92*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(bn);
93*c8dee2aaSAndroid Build Coastguard Worker     outOpInfo->fBounds = bn->fBounds;
94*c8dee2aaSAndroid Build Coastguard Worker     outOpInfo->fProxyUniqueID    = bn->fProxyUniqueID;
95*c8dee2aaSAndroid Build Coastguard Worker     for (int j = 0; j < bn->fChildren.size(); j++) {
96*c8dee2aaSAndroid Build Coastguard Worker         OpInfo::Op& outOp = outOpInfo->fOps.push_back();
97*c8dee2aaSAndroid Build Coastguard Worker         const Op* currentOp = bn->fChildren[j];
98*c8dee2aaSAndroid Build Coastguard Worker         outOp.fBounds = currentOp->fBounds;
99*c8dee2aaSAndroid Build Coastguard Worker         outOp.fClientID = currentOp->fClientID;
100*c8dee2aaSAndroid Build Coastguard Worker     }
101*c8dee2aaSAndroid Build Coastguard Worker }
102*c8dee2aaSAndroid Build Coastguard Worker 
getBoundsByClientID(TArray<OpInfo> * outInfo,int clientID)103*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::getBoundsByClientID(TArray<OpInfo>* outInfo, int clientID) {
104*c8dee2aaSAndroid Build Coastguard Worker     Ops** opsLookup = fClientIDLookup.find(clientID);
105*c8dee2aaSAndroid Build Coastguard Worker     if (opsLookup) {
106*c8dee2aaSAndroid Build Coastguard Worker         // We track which oplistID we're currently looking at.  If it changes, then we need to push
107*c8dee2aaSAndroid Build Coastguard Worker         // back a new op info struct.  We happen to know that ops are in sequential order in the
108*c8dee2aaSAndroid Build Coastguard Worker         // oplist, otherwise we'd have to do more bookkeeping
109*c8dee2aaSAndroid Build Coastguard Worker         int currentOpsTaskID = kGrAuditTrailInvalidID;
110*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < (*opsLookup)->size(); i++) {
111*c8dee2aaSAndroid Build Coastguard Worker             const Op* op = (**opsLookup)[i];
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker             // Because we will copy out all of the ops associated with a given op list id everytime
114*c8dee2aaSAndroid Build Coastguard Worker             // the id changes, we only have to update our struct when the id changes.
115*c8dee2aaSAndroid Build Coastguard Worker             if (kGrAuditTrailInvalidID == currentOpsTaskID || op->fOpsTaskID != currentOpsTaskID) {
116*c8dee2aaSAndroid Build Coastguard Worker                 OpInfo& outOpInfo = outInfo->push_back();
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker                 // copy out all of the ops so the client can display them even if they have a
119*c8dee2aaSAndroid Build Coastguard Worker                 // different clientID
120*c8dee2aaSAndroid Build Coastguard Worker                 this->copyOutFromOpsTask(&outOpInfo, op->fOpsTaskID);
121*c8dee2aaSAndroid Build Coastguard Worker             }
122*c8dee2aaSAndroid Build Coastguard Worker         }
123*c8dee2aaSAndroid Build Coastguard Worker     }
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker 
getBoundsByOpsTaskID(OpInfo * outInfo,int opsTaskID)126*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::getBoundsByOpsTaskID(OpInfo* outInfo, int opsTaskID) {
127*c8dee2aaSAndroid Build Coastguard Worker     this->copyOutFromOpsTask(outInfo, opsTaskID);
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker 
fullReset()130*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::fullReset() {
131*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(fEnabled);
132*c8dee2aaSAndroid Build Coastguard Worker     fOpsTask.clear();
133*c8dee2aaSAndroid Build Coastguard Worker     fIDLookup.reset();
134*c8dee2aaSAndroid Build Coastguard Worker     // free all client ops
135*c8dee2aaSAndroid Build Coastguard Worker     fClientIDLookup.foreach ([](const int&, Ops** ops) { delete *ops; });
136*c8dee2aaSAndroid Build Coastguard Worker     fClientIDLookup.reset();
137*c8dee2aaSAndroid Build Coastguard Worker     fOpPool.clear();  // must be last, frees all of the memory
138*c8dee2aaSAndroid Build Coastguard Worker }
139*c8dee2aaSAndroid Build Coastguard Worker 
140*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_ENABLE_DUMP_GPU
141*c8dee2aaSAndroid Build Coastguard Worker #include "src/utils/SkJSONWriter.h"
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
JsonifyTArray(SkJSONWriter & writer,const char * name,const T & array)144*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::JsonifyTArray(SkJSONWriter& writer, const char* name, const T& array) {
145*c8dee2aaSAndroid Build Coastguard Worker     if (array.size()) {
146*c8dee2aaSAndroid Build Coastguard Worker         writer.beginArray(name);
147*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < array.size(); i++) {
148*c8dee2aaSAndroid Build Coastguard Worker             // Handle sentinel nullptrs
149*c8dee2aaSAndroid Build Coastguard Worker             if (array[i]) {
150*c8dee2aaSAndroid Build Coastguard Worker                 array[i]->toJson(writer);
151*c8dee2aaSAndroid Build Coastguard Worker             }
152*c8dee2aaSAndroid Build Coastguard Worker         }
153*c8dee2aaSAndroid Build Coastguard Worker         writer.endArray();
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker }
156*c8dee2aaSAndroid Build Coastguard Worker 
toJson(SkJSONWriter & writer) const157*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::toJson(SkJSONWriter& writer) const {
158*c8dee2aaSAndroid Build Coastguard Worker     writer.beginObject();
159*c8dee2aaSAndroid Build Coastguard Worker     JsonifyTArray(writer, "Ops", fOpsTask);
160*c8dee2aaSAndroid Build Coastguard Worker     writer.endObject();
161*c8dee2aaSAndroid Build Coastguard Worker }
162*c8dee2aaSAndroid Build Coastguard Worker 
toJson(SkJSONWriter & writer,int clientID) const163*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::toJson(SkJSONWriter& writer, int clientID) const {
164*c8dee2aaSAndroid Build Coastguard Worker     writer.beginObject();
165*c8dee2aaSAndroid Build Coastguard Worker     Ops** ops = fClientIDLookup.find(clientID);
166*c8dee2aaSAndroid Build Coastguard Worker     if (ops) {
167*c8dee2aaSAndroid Build Coastguard Worker         JsonifyTArray(writer, "Ops", **ops);
168*c8dee2aaSAndroid Build Coastguard Worker     }
169*c8dee2aaSAndroid Build Coastguard Worker     writer.endObject();
170*c8dee2aaSAndroid Build Coastguard Worker }
171*c8dee2aaSAndroid Build Coastguard Worker 
skrect_to_json(SkJSONWriter & writer,const char * name,const SkRect & rect)172*c8dee2aaSAndroid Build Coastguard Worker static void skrect_to_json(SkJSONWriter& writer, const char* name, const SkRect& rect) {
173*c8dee2aaSAndroid Build Coastguard Worker     writer.beginObject(name);
174*c8dee2aaSAndroid Build Coastguard Worker     writer.appendFloat("Left", rect.fLeft);
175*c8dee2aaSAndroid Build Coastguard Worker     writer.appendFloat("Right", rect.fRight);
176*c8dee2aaSAndroid Build Coastguard Worker     writer.appendFloat("Top", rect.fTop);
177*c8dee2aaSAndroid Build Coastguard Worker     writer.appendFloat("Bottom", rect.fBottom);
178*c8dee2aaSAndroid Build Coastguard Worker     writer.endObject();
179*c8dee2aaSAndroid Build Coastguard Worker }
180*c8dee2aaSAndroid Build Coastguard Worker 
toJson(SkJSONWriter & writer) const181*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::Op::toJson(SkJSONWriter& writer) const {
182*c8dee2aaSAndroid Build Coastguard Worker     writer.beginObject();
183*c8dee2aaSAndroid Build Coastguard Worker     writer.appendString("Name", fName);
184*c8dee2aaSAndroid Build Coastguard Worker     writer.appendS32("ClientID", fClientID);
185*c8dee2aaSAndroid Build Coastguard Worker     writer.appendS32("OpsTaskID", fOpsTaskID);
186*c8dee2aaSAndroid Build Coastguard Worker     writer.appendS32("ChildID", fChildID);
187*c8dee2aaSAndroid Build Coastguard Worker     skrect_to_json(writer, "Bounds", fBounds);
188*c8dee2aaSAndroid Build Coastguard Worker     if (fStackTrace.size()) {
189*c8dee2aaSAndroid Build Coastguard Worker         writer.beginArray("Stack");
190*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < fStackTrace.size(); i++) {
191*c8dee2aaSAndroid Build Coastguard Worker             writer.appendString(fStackTrace[i]);
192*c8dee2aaSAndroid Build Coastguard Worker         }
193*c8dee2aaSAndroid Build Coastguard Worker         writer.endArray();
194*c8dee2aaSAndroid Build Coastguard Worker     }
195*c8dee2aaSAndroid Build Coastguard Worker     writer.endObject();
196*c8dee2aaSAndroid Build Coastguard Worker }
197*c8dee2aaSAndroid Build Coastguard Worker 
toJson(SkJSONWriter & writer) const198*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::OpNode::toJson(SkJSONWriter& writer) const {
199*c8dee2aaSAndroid Build Coastguard Worker     writer.beginObject();
200*c8dee2aaSAndroid Build Coastguard Worker     writer.appendU32("ProxyID", fProxyUniqueID.asUInt());
201*c8dee2aaSAndroid Build Coastguard Worker     skrect_to_json(writer, "Bounds", fBounds);
202*c8dee2aaSAndroid Build Coastguard Worker     JsonifyTArray(writer, "Ops", fChildren);
203*c8dee2aaSAndroid Build Coastguard Worker     writer.endObject();
204*c8dee2aaSAndroid Build Coastguard Worker }
205*c8dee2aaSAndroid Build Coastguard Worker #else
206*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
JsonifyTArray(SkJSONWriter & writer,const char * name,const T & array)207*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::JsonifyTArray(SkJSONWriter& writer, const char* name, const T& array) {}
toJson(SkJSONWriter & writer) const208*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::toJson(SkJSONWriter& writer) const {}
toJson(SkJSONWriter & writer,int clientID) const209*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::toJson(SkJSONWriter& writer, int clientID) const {}
toJson(SkJSONWriter & writer) const210*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::Op::toJson(SkJSONWriter& writer) const {}
toJson(SkJSONWriter & writer) const211*c8dee2aaSAndroid Build Coastguard Worker void GrAuditTrail::OpNode::toJson(SkJSONWriter& writer) const {}
212*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_ENABLE_DUMP_GPU
213