blob: 750890a7e49867a32848435dae8907933e6d8e62 [file] [log] [blame]
joshualitt27a48dc2016-01-08 07:19:47 -08001/*
2 * Copyright 2016 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#include "GrAuditTrail.h"
Brian Salomon89527432016-12-16 09:52:16 -05009#include "ops/GrOp.h"
Brian Osmand8a90f92019-01-28 13:41:19 -050010#include "SkJSONWriter.h"
joshualitt27a48dc2016-01-08 07:19:47 -080011
joshualittb95c7722016-02-29 07:44:02 -080012const int GrAuditTrail::kGrAuditTrailInvalidID = -1;
13
Robert Phillips318c4192017-05-17 09:36:38 -040014void GrAuditTrail::addOp(const GrOp* op, GrRenderTargetProxy::UniqueID proxyID) {
joshualittdf3f2b02016-03-01 07:47:56 -080015 SkASSERT(fEnabled);
Brian Salomon42ad83a2016-12-20 16:14:45 -050016 Op* auditOp = new Op;
17 fOpPool.emplace_back(auditOp);
18 auditOp->fName = op->name();
19 auditOp->fBounds = op->bounds();
20 auditOp->fClientID = kGrAuditTrailInvalidID;
21 auditOp->fOpListID = kGrAuditTrailInvalidID;
22 auditOp->fChildID = kGrAuditTrailInvalidID;
halcanary9d524f22016-03-29 09:03:52 -070023
joshualittf55c3642016-03-02 08:11:34 -080024 // consume the current stack trace if any
Brian Salomon42ad83a2016-12-20 16:14:45 -050025 auditOp->fStackTrace = fCurrentStackTrace;
joshualittf55c3642016-03-02 08:11:34 -080026 fCurrentStackTrace.reset();
halcanary9d524f22016-03-29 09:03:52 -070027
joshualittdf3f2b02016-03-01 07:47:56 -080028 if (fClientID != kGrAuditTrailInvalidID) {
Brian Salomon42ad83a2016-12-20 16:14:45 -050029 auditOp->fClientID = fClientID;
30 Ops** opsLookup = fClientIDLookup.find(fClientID);
31 Ops* ops = nullptr;
32 if (!opsLookup) {
33 ops = new Ops;
34 fClientIDLookup.set(fClientID, ops);
joshualittdf3f2b02016-03-01 07:47:56 -080035 } else {
Brian Salomon42ad83a2016-12-20 16:14:45 -050036 ops = *opsLookup;
joshualittdf3f2b02016-03-01 07:47:56 -080037 }
38
Brian Salomon42ad83a2016-12-20 16:14:45 -050039 ops->push_back(auditOp);
joshualittdf3f2b02016-03-01 07:47:56 -080040 }
joshualittdf3f2b02016-03-01 07:47:56 -080041
Brian Salomon42ad83a2016-12-20 16:14:45 -050042 // Our algorithm doesn't bother to reorder inside of an OpNode so the ChildID will start at 0
43 auditOp->fOpListID = fOpList.count();
44 auditOp->fChildID = 0;
joshualittb95c7722016-02-29 07:44:02 -080045
Brian Salomon42ad83a2016-12-20 16:14:45 -050046 // We use the op pointer as a key to find the OpNode we are 'glomming' ops onto
47 fIDLookup.set(op->uniqueID(), auditOp->fOpListID);
Robert Phillips318c4192017-05-17 09:36:38 -040048 OpNode* opNode = new OpNode(proxyID);
Brian Salomon42ad83a2016-12-20 16:14:45 -050049 opNode->fBounds = op->bounds();
50 opNode->fChildren.push_back(auditOp);
51 fOpList.emplace_back(opNode);
joshualitt18d6b752016-02-26 08:07:50 -080052}
53
Brian Salomon42ad83a2016-12-20 16:14:45 -050054void GrAuditTrail::opsCombined(const GrOp* consumer, const GrOp* consumed) {
55 // Look up the op we are going to glom onto
joshualittb0666ad2016-03-08 10:43:41 -080056 int* indexPtr = fIDLookup.find(consumer->uniqueID());
57 SkASSERT(indexPtr);
58 int index = *indexPtr;
Brian Salomon42ad83a2016-12-20 16:14:45 -050059 SkASSERT(index < fOpList.count() && fOpList[index]);
60 OpNode& consumerOp = *fOpList[index];
joshualittb0666ad2016-03-08 10:43:41 -080061
Brian Salomon42ad83a2016-12-20 16:14:45 -050062 // Look up the op which will be glommed
joshualittb0666ad2016-03-08 10:43:41 -080063 int* consumedPtr = fIDLookup.find(consumed->uniqueID());
64 SkASSERT(consumedPtr);
65 int consumedIndex = *consumedPtr;
Brian Salomon42ad83a2016-12-20 16:14:45 -050066 SkASSERT(consumedIndex < fOpList.count() && fOpList[consumedIndex]);
67 OpNode& consumedOp = *fOpList[consumedIndex];
joshualittb0666ad2016-03-08 10:43:41 -080068
Brian Salomon42ad83a2016-12-20 16:14:45 -050069 // steal all of consumed's ops
70 for (int i = 0; i < consumedOp.fChildren.count(); i++) {
71 Op* childOp = consumedOp.fChildren[i];
halcanary9d524f22016-03-29 09:03:52 -070072
Brian Salomon42ad83a2016-12-20 16:14:45 -050073 // set the ids for the child op
74 childOp->fOpListID = index;
75 childOp->fChildID = consumerOp.fChildren.count();
76 consumerOp.fChildren.push_back(childOp);
joshualittb0666ad2016-03-08 10:43:41 -080077 }
halcanary9d524f22016-03-29 09:03:52 -070078
joshualittb0666ad2016-03-08 10:43:41 -080079 // Update the bounds for the combineWith node
Brian Salomon42ad83a2016-12-20 16:14:45 -050080 consumerOp.fBounds = consumer->bounds();
joshualittb0666ad2016-03-08 10:43:41 -080081
Brian Salomon42ad83a2016-12-20 16:14:45 -050082 // remove the old node from our opList and clear the combinee's lookup
83 // NOTE: because we can't change the shape of the oplist, we use a sentinel
84 fOpList[consumedIndex].reset(nullptr);
joshualittb0666ad2016-03-08 10:43:41 -080085 fIDLookup.remove(consumed->uniqueID());
86}
87
Brian Salomon42ad83a2016-12-20 16:14:45 -050088void GrAuditTrail::copyOutFromOpList(OpInfo* outOpInfo, int opListID) {
89 SkASSERT(opListID < fOpList.count());
90 const OpNode* bn = fOpList[opListID].get();
joshualittb0666ad2016-03-08 10:43:41 -080091 SkASSERT(bn);
Brian Salomon42ad83a2016-12-20 16:14:45 -050092 outOpInfo->fBounds = bn->fBounds;
Robert Phillipsf7a72612017-03-31 10:03:45 -040093 outOpInfo->fProxyUniqueID = bn->fProxyUniqueID;
joshualitt46b301d2016-03-02 08:32:37 -080094 for (int j = 0; j < bn->fChildren.count(); j++) {
Brian Salomon42ad83a2016-12-20 16:14:45 -050095 OpInfo::Op& outOp = outOpInfo->fOps.push_back();
96 const Op* currentOp = bn->fChildren[j];
97 outOp.fBounds = currentOp->fBounds;
98 outOp.fClientID = currentOp->fClientID;
joshualitt46b301d2016-03-02 08:32:37 -080099 }
100}
101
Brian Salomon42ad83a2016-12-20 16:14:45 -0500102void GrAuditTrail::getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID) {
103 Ops** opsLookup = fClientIDLookup.find(clientID);
104 if (opsLookup) {
105 // We track which oplistID we're currently looking at. If it changes, then we need to push
106 // back a new op info struct. We happen to know that ops are in sequential order in the
107 // oplist, otherwise we'd have to do more bookkeeping
108 int currentOpListID = kGrAuditTrailInvalidID;
109 for (int i = 0; i < (*opsLookup)->count(); i++) {
110 const Op* op = (**opsLookup)[i];
joshualitt10d8fc22016-02-29 11:15:06 -0800111
Brian Salomon42ad83a2016-12-20 16:14:45 -0500112 // Because we will copy out all of the ops associated with a given op list id everytime
113 // the id changes, we only have to update our struct when the id changes.
114 if (kGrAuditTrailInvalidID == currentOpListID || op->fOpListID != currentOpListID) {
115 OpInfo& outOpInfo = outInfo->push_back();
halcanary9d524f22016-03-29 09:03:52 -0700116
Brian Salomon42ad83a2016-12-20 16:14:45 -0500117 // copy out all of the ops so the client can display them even if they have a
118 // different clientID
119 this->copyOutFromOpList(&outOpInfo, op->fOpListID);
joshualitt10d8fc22016-02-29 11:15:06 -0800120 }
121 }
122 }
123}
124
Brian Salomon42ad83a2016-12-20 16:14:45 -0500125void GrAuditTrail::getBoundsByOpListID(OpInfo* outInfo, int opListID) {
126 this->copyOutFromOpList(outInfo, opListID);
joshualitt46b301d2016-03-02 08:32:37 -0800127}
128
joshualittdf3f2b02016-03-01 07:47:56 -0800129void GrAuditTrail::fullReset() {
130 SkASSERT(fEnabled);
Brian Salomon42ad83a2016-12-20 16:14:45 -0500131 fOpList.reset();
joshualittdf3f2b02016-03-01 07:47:56 -0800132 fIDLookup.reset();
Brian Salomon42ad83a2016-12-20 16:14:45 -0500133 // free all client ops
134 fClientIDLookup.foreach ([](const int&, Ops** ops) { delete *ops; });
joshualittdf3f2b02016-03-01 07:47:56 -0800135 fClientIDLookup.reset();
Brian Salomon42ad83a2016-12-20 16:14:45 -0500136 fOpPool.reset(); // must be last, frees all of the memory
joshualittdf3f2b02016-03-01 07:47:56 -0800137}
joshualitt10d8fc22016-02-29 11:15:06 -0800138
joshualitt18d6b752016-02-26 08:07:50 -0800139template <typename T>
Brian Osmand8a90f92019-01-28 13:41:19 -0500140void GrAuditTrail::JsonifyTArray(SkJSONWriter& writer, const char* name, const T& array) {
joshualitt87a721b2016-01-12 12:59:28 -0800141 if (array.count()) {
Brian Osmand8a90f92019-01-28 13:41:19 -0500142 writer.beginArray(name);
joshualitt87a721b2016-01-12 12:59:28 -0800143 for (int i = 0; i < array.count(); i++) {
joshualittb0666ad2016-03-08 10:43:41 -0800144 // Handle sentinel nullptrs
joshualittae47aee2016-03-10 13:29:36 -0800145 if (array[i]) {
Brian Osmand8a90f92019-01-28 13:41:19 -0500146 array[i]->toJson(writer);
joshualitt87a721b2016-01-12 12:59:28 -0800147 }
joshualitt27a48dc2016-01-08 07:19:47 -0800148 }
Brian Osmand8a90f92019-01-28 13:41:19 -0500149 writer.endArray();
joshualitt27a48dc2016-01-08 07:19:47 -0800150 }
joshualitt086cee12016-01-12 06:45:24 -0800151}
152
Brian Osmand8a90f92019-01-28 13:41:19 -0500153void GrAuditTrail::toJson(SkJSONWriter& writer) const {
154 writer.beginObject();
155 JsonifyTArray(writer, "Ops", fOpList);
156 writer.endObject();
joshualitt086cee12016-01-12 06:45:24 -0800157}
158
Brian Osmand8a90f92019-01-28 13:41:19 -0500159void GrAuditTrail::toJson(SkJSONWriter& writer, int clientID) const {
160 writer.beginObject();
Brian Salomon42ad83a2016-12-20 16:14:45 -0500161 Ops** ops = fClientIDLookup.find(clientID);
162 if (ops) {
Brian Osmand8a90f92019-01-28 13:41:19 -0500163 JsonifyTArray(writer, "Ops", **ops);
joshualittb95c7722016-02-29 07:44:02 -0800164 }
Brian Osmand8a90f92019-01-28 13:41:19 -0500165 writer.endObject();
joshualittb95c7722016-02-29 07:44:02 -0800166}
167
Brian Osmand8a90f92019-01-28 13:41:19 -0500168static void skrect_to_json(SkJSONWriter& writer, const char* name, const SkRect& rect) {
169 writer.beginObject(name);
170 writer.appendFloat("Left", rect.fLeft);
171 writer.appendFloat("Right", rect.fRight);
172 writer.appendFloat("Top", rect.fTop);
173 writer.appendFloat("Bottom", rect.fBottom);
174 writer.endObject();
joshualitt27a48dc2016-01-08 07:19:47 -0800175}
176
Brian Osmand8a90f92019-01-28 13:41:19 -0500177void GrAuditTrail::Op::toJson(SkJSONWriter& writer) const {
178 writer.beginObject();
179 writer.appendString("Name", fName.c_str());
180 writer.appendS32("ClientID", fClientID);
181 writer.appendS32("OpListID", fOpListID);
182 writer.appendS32("ChildID", fChildID);
183 skrect_to_json(writer, "Bounds", fBounds);
joshualittf55c3642016-03-02 08:11:34 -0800184 if (fStackTrace.count()) {
Brian Osmand8a90f92019-01-28 13:41:19 -0500185 writer.beginArray("Stack");
joshualittf55c3642016-03-02 08:11:34 -0800186 for (int i = 0; i < fStackTrace.count(); i++) {
Brian Osmand8a90f92019-01-28 13:41:19 -0500187 writer.appendString(fStackTrace[i].c_str());
joshualittf55c3642016-03-02 08:11:34 -0800188 }
Brian Osmand8a90f92019-01-28 13:41:19 -0500189 writer.endArray();
joshualittf55c3642016-03-02 08:11:34 -0800190 }
Brian Osmand8a90f92019-01-28 13:41:19 -0500191 writer.endObject();
joshualittb95c7722016-02-29 07:44:02 -0800192}
193
Brian Osmand8a90f92019-01-28 13:41:19 -0500194void GrAuditTrail::OpNode::toJson(SkJSONWriter& writer) const {
195 writer.beginObject();
196 writer.appendU32("ProxyID", fProxyUniqueID.asUInt());
197 skrect_to_json(writer, "Bounds", fBounds);
198 JsonifyTArray(writer, "Ops", fChildren);
199 writer.endObject();
joshualitt086cee12016-01-12 06:45:24 -0800200}