OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrAuditTrail_DEFINED | 8 #ifndef GrAuditTrail_DEFINED |
9 #define GrAuditTrail_DEFINED | 9 #define GrAuditTrail_DEFINED |
10 | 10 |
(...skipping 10 matching lines...) Expand all Loading... |
21 * to json. | 21 * to json. |
22 * | 22 * |
23 * Capturing this information is expensive and consumes a lot of memory, therefo
re it is important | 23 * Capturing this information is expensive and consumes a lot of memory, therefo
re it is important |
24 * to enable auditing only when required and disable it promptly. The AutoEnable
class helps to | 24 * to enable auditing only when required and disable it promptly. The AutoEnable
class helps to |
25 * ensure that the audit trail is disabled in a timely fashion. Once the informa
tion has been dealt | 25 * ensure that the audit trail is disabled in a timely fashion. Once the informa
tion has been dealt |
26 * with, be sure to call reset(), or the log will simply keep growing. | 26 * with, be sure to call reset(), or the log will simply keep growing. |
27 */ | 27 */ |
28 class GrAuditTrail { | 28 class GrAuditTrail { |
29 public: | 29 public: |
30 GrAuditTrail() | 30 GrAuditTrail() |
31 : fClientID(kInvalidID) | 31 : fEnabled(false) |
32 , fEnabled(false) {} | 32 , fUniqueID(0) {} |
| 33 |
| 34 class AutoFrame { |
| 35 public: |
| 36 AutoFrame(GrAuditTrail* auditTrail, const char* name) |
| 37 : fAuditTrail(auditTrail) { |
| 38 if (fAuditTrail->fEnabled) { |
| 39 fAuditTrail->pushFrame(name); |
| 40 } |
| 41 } |
| 42 |
| 43 ~AutoFrame() { |
| 44 if (fAuditTrail->fEnabled) { |
| 45 fAuditTrail->popFrame(); |
| 46 } |
| 47 } |
| 48 |
| 49 private: |
| 50 GrAuditTrail* fAuditTrail; |
| 51 }; |
33 | 52 |
34 class AutoEnable { | 53 class AutoEnable { |
35 public: | 54 public: |
36 AutoEnable(GrAuditTrail* auditTrail) | 55 AutoEnable(GrAuditTrail* auditTrail) |
37 : fAuditTrail(auditTrail) { | 56 : fAuditTrail(auditTrail) { |
38 SkASSERT(!fAuditTrail->isEnabled()); | 57 SkASSERT(!fAuditTrail->isEnabled()); |
39 fAuditTrail->setEnabled(true); | 58 fAuditTrail->setEnabled(true); |
40 } | 59 } |
41 | 60 |
42 ~AutoEnable() { | 61 ~AutoEnable() { |
(...skipping 14 matching lines...) Expand all Loading... |
57 | 76 |
58 ~AutoManageBatchList() { | 77 ~AutoManageBatchList() { |
59 fAuditTrail->fullReset(); | 78 fAuditTrail->fullReset(); |
60 } | 79 } |
61 | 80 |
62 private: | 81 private: |
63 AutoEnable fAutoEnable; | 82 AutoEnable fAutoEnable; |
64 GrAuditTrail* fAuditTrail; | 83 GrAuditTrail* fAuditTrail; |
65 }; | 84 }; |
66 | 85 |
67 class AutoCollectBatches { | 86 void pushFrame(const char* name) { |
68 public: | 87 SkASSERT(fEnabled); |
69 AutoCollectBatches(GrAuditTrail* auditTrail, int clientID) | 88 Frame* frame = new Frame; |
70 : fAutoEnable(auditTrail) | 89 fEvents.emplace_back(frame); |
71 , fAuditTrail(auditTrail) { | 90 if (fStack.empty()) { |
72 fAuditTrail->setClientID(clientID); | 91 fFrames.push_back(frame); |
| 92 } else { |
| 93 fStack.back()->fChildren.push_back(frame); |
73 } | 94 } |
74 | 95 |
75 ~AutoCollectBatches() { fAuditTrail->setClientID(kInvalidID); } | 96 frame->fUniqueID = fUniqueID++; |
| 97 frame->fName = name; |
| 98 fStack.push_back(frame); |
| 99 } |
76 | 100 |
77 private: | 101 void popFrame() { |
78 AutoEnable fAutoEnable; | 102 SkASSERT(fEnabled); |
79 GrAuditTrail* fAuditTrail; | 103 fStack.pop_back(); |
80 }; | 104 } |
81 | 105 |
82 void addBatch(const char* name, const SkRect& bounds) { | 106 void addBatch(const char* name, const SkRect& bounds) { |
83 SkASSERT(fEnabled); | 107 SkASSERT(fEnabled && !fStack.empty()); |
84 Batch* batch = new Batch; | 108 Batch* batch = new Batch; |
85 fBatchPool.emplace_back(batch); | 109 fEvents.emplace_back(batch); |
| 110 fStack.back()->fChildren.push_back(batch); |
86 batch->fName = name; | 111 batch->fName = name; |
87 batch->fBounds = bounds; | 112 batch->fBounds = bounds; |
88 batch->fClientID = kInvalidID; | |
89 batch->fBatchListID = kInvalidID; | |
90 batch->fChildID = kInvalidID; | |
91 fCurrentBatch = batch; | 113 fCurrentBatch = batch; |
92 | |
93 if (fClientID != kInvalidID) { | |
94 batch->fClientID = fClientID; | |
95 Batches** batchesLookup = fClientIDLookup.find(fClientID); | |
96 Batches* batches = nullptr; | |
97 if (!batchesLookup) { | |
98 batches = new Batches; | |
99 fClientIDLookup.set(fClientID, batches); | |
100 } else { | |
101 batches = *batchesLookup; | |
102 } | |
103 | |
104 batches->push_back(fCurrentBatch); | |
105 } | |
106 } | 114 } |
107 | 115 |
108 void batchingResultCombined(GrBatch* combiner); | 116 void batchingResultCombined(GrBatch* combiner); |
109 | 117 |
110 void batchingResultNew(GrBatch* batch); | 118 void batchingResultNew(GrBatch* batch); |
111 | 119 |
112 // Because batching is heavily dependent on sequence of draw calls, these ca
lls will only | 120 SkString toJson(bool batchList = false, bool prettyPrint = false) const; |
113 // produce valid information for the given draw sequence which preceeded the
m. | |
114 // Specifically, future draw calls may change the batching and thus would in
validate | |
115 // the json. What this means is that for some sequence of draw calls N, the
below toJson | |
116 // calls will only produce JSON which reflects N draw calls. This JSON may
or may not be | |
117 // accurate for N + 1 or N - 1 draws depending on the actual batching algori
thm used. | |
118 SkString toJson(bool prettyPrint = false) const; | |
119 | |
120 // returns a json string of all of the batches associated with a given clien
t id | |
121 SkString toJson(int clientID, bool prettyPrint = false) const; | |
122 | 121 |
123 bool isEnabled() { return fEnabled; } | 122 bool isEnabled() { return fEnabled; } |
124 void setEnabled(bool enabled) { fEnabled = enabled; } | 123 void setEnabled(bool enabled) { fEnabled = enabled; } |
125 | 124 |
126 void setClientID(int clientID) { fClientID = clientID; } | 125 void reset() { |
| 126 SkASSERT(fEnabled && fStack.empty()); |
| 127 fFrames.reset(); |
| 128 } |
| 129 |
| 130 void resetBatchList() { |
| 131 SkASSERT(fEnabled); |
| 132 fBatches.reset(); |
| 133 fIDLookup.reset(); |
| 134 } |
127 | 135 |
128 void fullReset() { | 136 void fullReset() { |
129 SkASSERT(fEnabled); | 137 SkASSERT(fEnabled); |
130 fBatchList.reset(); | 138 this->reset(); |
131 fIDLookup.reset(); | 139 this->resetBatchList(); |
132 // free all client batches | 140 fEvents.reset(); // must be last, frees all of the memory |
133 fClientIDLookup.foreach([](const int&, Batches** batches) { delete *batc
hes; }); | |
134 fClientIDLookup.reset(); | |
135 fBatchPool.reset(); // must be last, frees all of the memory | |
136 } | 141 } |
137 | 142 |
138 static const int kInvalidID; | |
139 | |
140 private: | 143 private: |
141 // TODO if performance becomes an issue, we can move to using SkVarAlloc | 144 // TODO if performance becomes an issue, we can move to using SkVarAlloc |
142 struct Batch { | 145 struct Event { |
143 SkString toJson() const; | 146 virtual ~Event() {} |
144 SkString fName; | 147 virtual SkString toJson() const=0; |
| 148 |
| 149 const char* fName; |
| 150 uint64_t fUniqueID; |
| 151 }; |
| 152 |
| 153 struct Frame : public Event { |
| 154 SkString toJson() const override; |
| 155 SkTArray<Event*> fChildren; |
| 156 }; |
| 157 |
| 158 struct Batch : public Event { |
| 159 SkString toJson() const override; |
145 SkRect fBounds; | 160 SkRect fBounds; |
146 int fClientID; | 161 SkTArray<Batch*> fChildren; |
147 int fBatchListID; | |
148 int fChildID; | |
149 }; | 162 }; |
150 typedef SkTArray<SkAutoTDelete<Batch>, true> BatchPool; | 163 typedef SkTArray<SkAutoTDelete<Event>, true> EventArrayPool; |
151 | |
152 typedef SkTArray<Batch*> Batches; | |
153 | |
154 struct BatchNode { | |
155 SkString toJson() const; | |
156 SkRect fBounds; | |
157 Batches fChildren; | |
158 }; | |
159 typedef SkTArray<SkAutoTDelete<BatchNode>, true> BatchList; | |
160 | 164 |
161 template <typename T> | 165 template <typename T> |
162 static void JsonifyTArray(SkString* json, const char* name, const T& array, | 166 static void JsonifyTArray(SkString* json, const char* name, const T& array, |
163 bool addComma); | 167 bool addComma); |
164 | 168 |
| 169 // We store both an array of frames, and also a flatter array just of the ba
tches |
| 170 bool fEnabled; |
| 171 EventArrayPool fEvents; // manages the lifetimes of the events |
| 172 SkTArray<Event*> fFrames; |
| 173 SkTArray<Frame*> fStack; |
| 174 uint64_t fUniqueID; |
| 175 |
165 Batch* fCurrentBatch; | 176 Batch* fCurrentBatch; |
166 BatchPool fBatchPool; | |
167 SkTHashMap<GrBatch*, int> fIDLookup; | 177 SkTHashMap<GrBatch*, int> fIDLookup; |
168 SkTHashMap<int, Batches*> fClientIDLookup; | 178 SkTArray<Batch*> fBatches; |
169 BatchList fBatchList; | |
170 | |
171 // The client cas pass in an optional client ID which we will use to mark th
e batches | |
172 int fClientID; | |
173 bool fEnabled; | |
174 }; | 179 }; |
175 | 180 |
176 #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \ | 181 #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \ |
177 if (audit_trail->isEnabled()) { \ | 182 if (audit_trail->isEnabled()) { \ |
178 audit_trail->invoke(__VA_ARGS__); \ | 183 audit_trail->invoke(__VA_ARGS__); \ |
179 } | 184 } |
180 | 185 |
181 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \ | 186 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \ |
182 // TODO fill out the frame stuff | 187 GrAuditTrail::AutoFrame SK_MACRO_APPEND_LINE(auto_frame)(audit_trail, framen
ame); |
183 //GrAuditTrail::AutoFrame SK_MACRO_APPEND_LINE(auto_frame)(audit_trail, fram
ename); | |
184 | 188 |
185 #define GR_AUDIT_TRAIL_RESET(audit_trail) \ | 189 #define GR_AUDIT_TRAIL_RESET(audit_trail) \ |
186 //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, reset); | 190 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, reset); |
187 | 191 |
188 #define GR_AUDIT_TRAIL_ADDBATCH(audit_trail, batchname, bounds) \ | 192 #define GR_AUDIT_TRAIL_ADDBATCH(audit_trail, batchname, bounds) \ |
189 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addBatch, batchname, bounds); | 193 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addBatch, batchname, bounds); |
190 | 194 |
191 #define GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(audit_trail, combiner) \ | 195 #define GR_AUDIT_TRAIL_BATCHING_RESULT_COMBINED(audit_trail, combiner) \ |
192 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, batchingResultCombined, combiner); | 196 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, batchingResultCombined, combiner); |
193 | 197 |
194 #define GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(audit_trail, batch) \ | 198 #define GR_AUDIT_TRAIL_BATCHING_RESULT_NEW(audit_trail, batch) \ |
195 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, batchingResultNew, batch); | 199 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, batchingResultNew, batch); |
196 | 200 |
197 #endif | 201 #endif |
OLD | NEW |