Line data Source code
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 :
8 : #ifndef GrAuditTrail_DEFINED
9 : #define GrAuditTrail_DEFINED
10 :
11 : #include "GrConfig.h"
12 : #include "GrGpuResource.h"
13 : #include "GrRenderTargetProxy.h"
14 : #include "SkRect.h"
15 : #include "SkString.h"
16 : #include "SkTArray.h"
17 : #include "SkTHash.h"
18 :
19 : class GrOp;
20 :
21 : /*
22 : * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them
23 : * to json.
24 : *
25 : * Capturing this information is expensive and consumes a lot of memory, therefore it is important
26 : * to enable auditing only when required and disable it promptly. The AutoEnable class helps to
27 : * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt
28 : * with, be sure to call reset(), or the log will simply keep growing.
29 : */
30 0 : class GrAuditTrail {
31 : public:
32 0 : GrAuditTrail()
33 0 : : fClientID(kGrAuditTrailInvalidID)
34 0 : , fEnabled(false) {}
35 :
36 : class AutoEnable {
37 : public:
38 : AutoEnable(GrAuditTrail* auditTrail)
39 : : fAuditTrail(auditTrail) {
40 : SkASSERT(!fAuditTrail->isEnabled());
41 : fAuditTrail->setEnabled(true);
42 : }
43 :
44 : ~AutoEnable() {
45 : SkASSERT(fAuditTrail->isEnabled());
46 : fAuditTrail->setEnabled(false);
47 : }
48 :
49 : private:
50 : GrAuditTrail* fAuditTrail;
51 : };
52 :
53 : class AutoManageOpList {
54 : public:
55 : AutoManageOpList(GrAuditTrail* auditTrail)
56 : : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {}
57 :
58 : ~AutoManageOpList() { fAuditTrail->fullReset(); }
59 :
60 : private:
61 : AutoEnable fAutoEnable;
62 : GrAuditTrail* fAuditTrail;
63 : };
64 :
65 : class AutoCollectOps {
66 : public:
67 : AutoCollectOps(GrAuditTrail* auditTrail, int clientID)
68 : : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {
69 : fAuditTrail->setClientID(clientID);
70 : }
71 :
72 : ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); }
73 :
74 : private:
75 : AutoEnable fAutoEnable;
76 : GrAuditTrail* fAuditTrail;
77 : };
78 :
79 0 : void pushFrame(const char* framename) {
80 0 : SkASSERT(fEnabled);
81 0 : fCurrentStackTrace.push_back(SkString(framename));
82 0 : }
83 :
84 : void addOp(const GrOp*,
85 : GrGpuResource::UniqueID resourceID,
86 : GrRenderTargetProxy::UniqueID proxyID);
87 :
88 : void opsCombined(const GrOp* consumer, const GrOp* consumed);
89 :
90 : // Because op combining is heavily dependent on sequence of draw calls, these calls will only
91 : // produce valid information for the given draw sequence which preceeded them. Specifically, ops
92 : // of future draw calls may combine with previous ops and thus would invalidate the json. What
93 : // this means is that for some sequence of draw calls N, the below toJson calls will only
94 : // produce JSON which reflects N draw calls. This JSON may or may not be accurate for N + 1 or
95 : // N - 1 draws depending on the actual combining algorithm used.
96 : SkString toJson(bool prettyPrint = false) const;
97 :
98 : // returns a json string of all of the ops associated with a given client id
99 : SkString toJson(int clientID, bool prettyPrint = false) const;
100 :
101 0 : bool isEnabled() { return fEnabled; }
102 : void setEnabled(bool enabled) { fEnabled = enabled; }
103 :
104 : void setClientID(int clientID) { fClientID = clientID; }
105 :
106 : // We could just return our internal bookkeeping struct if copying the data out becomes
107 : // a performance issue, but until then its nice to decouple
108 0 : struct OpInfo {
109 : // Will the resourceID comparison yield the same decision as the proxyID comparison?
110 : bool sameDecision(GrGpuResource::UniqueID resourceUniqueID,
111 : GrSurfaceProxy::UniqueID proxyUniqueID) const {
112 : return (fResourceUniqueID == resourceUniqueID) ==
113 : (fProxyUniqueID == proxyUniqueID);
114 : }
115 :
116 : struct Op {
117 : int fClientID;
118 : SkRect fBounds;
119 : };
120 :
121 : SkRect fBounds;
122 : // MDB TODO: remove fResourceUniqueID
123 : GrGpuResource::UniqueID fResourceUniqueID;
124 : GrSurfaceProxy::UniqueID fProxyUniqueID;
125 : SkTArray<Op> fOps;
126 : };
127 :
128 : void getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID);
129 : void getBoundsByOpListID(OpInfo* outInfo, int opListID);
130 :
131 : void fullReset();
132 :
133 : static const int kGrAuditTrailInvalidID;
134 :
135 : private:
136 : // TODO if performance becomes an issue, we can move to using SkVarAlloc
137 0 : struct Op {
138 : SkString toJson() const;
139 : SkString fName;
140 : SkTArray<SkString> fStackTrace;
141 : SkRect fBounds;
142 : int fClientID;
143 : int fOpListID;
144 : int fChildID;
145 : };
146 : typedef SkTArray<std::unique_ptr<Op>, true> OpPool;
147 :
148 : typedef SkTArray<Op*> Ops;
149 :
150 0 : struct OpNode {
151 0 : OpNode(const GrGpuResource::UniqueID& resourceID, const GrSurfaceProxy::UniqueID& proxyID)
152 0 : : fResourceUniqueID(resourceID)
153 0 : , fProxyUniqueID(proxyID) {
154 0 : }
155 : SkString toJson() const;
156 :
157 : SkRect fBounds;
158 : Ops fChildren;
159 : const GrGpuResource::UniqueID fResourceUniqueID;
160 : const GrSurfaceProxy::UniqueID fProxyUniqueID;
161 : };
162 : typedef SkTArray<std::unique_ptr<OpNode>, true> OpList;
163 :
164 : void copyOutFromOpList(OpInfo* outOpInfo, int opListID);
165 :
166 : template <typename T>
167 : static void JsonifyTArray(SkString* json, const char* name, const T& array,
168 : bool addComma);
169 :
170 : OpPool fOpPool;
171 : SkTHashMap<uint32_t, int> fIDLookup;
172 : SkTHashMap<int, Ops*> fClientIDLookup;
173 : OpList fOpList;
174 : SkTArray<SkString> fCurrentStackTrace;
175 :
176 : // The client can pass in an optional client ID which we will use to mark the ops
177 : int fClientID;
178 : bool fEnabled;
179 : };
180 :
181 : #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \
182 : if (audit_trail->isEnabled()) { \
183 : audit_trail->invoke(__VA_ARGS__); \
184 : }
185 :
186 : #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \
187 : GR_AUDIT_TRAIL_INVOKE_GUARD((audit_trail), pushFrame, framename);
188 :
189 : #define GR_AUDIT_TRAIL_RESET(audit_trail) \
190 : //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, fullReset);
191 :
192 : #define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, resource_id, proxy_id) \
193 : GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, resource_id, proxy_id);
194 :
195 : #define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \
196 : GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op);
197 :
198 : #define GR_AUDIT_TRAIL_OP_RESULT_NEW(audit_trail, op) // Doesn't do anything now, one day...
199 :
200 : #endif
|