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