• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 class GrAuditTrail {
31 public:
GrAuditTrail()32     GrAuditTrail()
33     : fClientID(kGrAuditTrailInvalidID)
34     , fEnabled(false) {}
35 
36     class AutoEnable {
37     public:
AutoEnable(GrAuditTrail * auditTrail)38         AutoEnable(GrAuditTrail* auditTrail)
39             : fAuditTrail(auditTrail) {
40             SkASSERT(!fAuditTrail->isEnabled());
41             fAuditTrail->setEnabled(true);
42         }
43 
~AutoEnable()44         ~AutoEnable() {
45             SkASSERT(fAuditTrail->isEnabled());
46             fAuditTrail->setEnabled(false);
47         }
48 
49     private:
50         GrAuditTrail* fAuditTrail;
51     };
52 
53     class AutoManageOpList {
54     public:
AutoManageOpList(GrAuditTrail * auditTrail)55         AutoManageOpList(GrAuditTrail* auditTrail)
56                 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {}
57 
~AutoManageOpList()58         ~AutoManageOpList() { fAuditTrail->fullReset(); }
59 
60     private:
61         AutoEnable fAutoEnable;
62         GrAuditTrail* fAuditTrail;
63     };
64 
65     class AutoCollectOps {
66     public:
AutoCollectOps(GrAuditTrail * auditTrail,int clientID)67         AutoCollectOps(GrAuditTrail* auditTrail, int clientID)
68                 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {
69             fAuditTrail->setClientID(clientID);
70         }
71 
~AutoCollectOps()72         ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); }
73 
74     private:
75         AutoEnable fAutoEnable;
76         GrAuditTrail* fAuditTrail;
77     };
78 
pushFrame(const char * framename)79     void pushFrame(const char* framename) {
80         SkASSERT(fEnabled);
81         fCurrentStackTrace.push_back(SkString(framename));
82     }
83 
84     void addOp(const GrOp*, GrRenderTargetProxy::UniqueID proxyID);
85 
86     void opsCombined(const GrOp* consumer, const GrOp* consumed);
87 
88     // Because op combining is heavily dependent on sequence of draw calls, these calls will only
89     // produce valid information for the given draw sequence which preceeded them. Specifically, ops
90     // of future draw calls may combine with previous ops and thus would invalidate the json. What
91     // this means is that for some sequence of draw calls N, the below toJson calls will only
92     // produce JSON which reflects N draw calls. This JSON may or may not be accurate for N + 1 or
93     // N - 1 draws depending on the actual combining algorithm used.
94     SkString toJson(bool prettyPrint = false) const;
95 
96     // returns a json string of all of the ops associated with a given client id
97     SkString toJson(int clientID, bool prettyPrint = false) const;
98 
isEnabled()99     bool isEnabled() { return fEnabled; }
setEnabled(bool enabled)100     void setEnabled(bool enabled) { fEnabled = enabled; }
101 
setClientID(int clientID)102     void setClientID(int clientID) { fClientID = clientID; }
103 
104     // We could just return our internal bookkeeping struct if copying the data out becomes
105     // a performance issue, but until then its nice to decouple
106     struct OpInfo {
107         struct Op {
108             int    fClientID;
109             SkRect fBounds;
110         };
111 
112         SkRect                   fBounds;
113         GrSurfaceProxy::UniqueID fProxyUniqueID;
114         SkTArray<Op>             fOps;
115     };
116 
117     void getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID);
118     void getBoundsByOpListID(OpInfo* outInfo, int opListID);
119 
120     void fullReset();
121 
122     static const int kGrAuditTrailInvalidID;
123 
124 private:
125     // TODO if performance becomes an issue, we can move to using SkVarAlloc
126     struct Op {
127         SkString toJson() const;
128         SkString fName;
129         SkTArray<SkString> fStackTrace;
130         SkRect fBounds;
131         int fClientID;
132         int fOpListID;
133         int fChildID;
134     };
135     typedef SkTArray<std::unique_ptr<Op>, true> OpPool;
136 
137     typedef SkTArray<Op*> Ops;
138 
139     struct OpNode {
OpNodeOpNode140         OpNode(const GrSurfaceProxy::UniqueID& proxyID) : fProxyUniqueID(proxyID) { }
141         SkString toJson() const;
142 
143         SkRect                         fBounds;
144         Ops                            fChildren;
145         const GrSurfaceProxy::UniqueID fProxyUniqueID;
146     };
147     typedef SkTArray<std::unique_ptr<OpNode>, true> OpList;
148 
149     void copyOutFromOpList(OpInfo* outOpInfo, int opListID);
150 
151     template <typename T>
152     static void JsonifyTArray(SkString* json, const char* name, const T& array,
153                               bool addComma);
154 
155     OpPool fOpPool;
156     SkTHashMap<uint32_t, int> fIDLookup;
157     SkTHashMap<int, Ops*> fClientIDLookup;
158     OpList fOpList;
159     SkTArray<SkString> fCurrentStackTrace;
160 
161     // The client can pass in an optional client ID which we will use to mark the ops
162     int fClientID;
163     bool fEnabled;
164 };
165 
166 #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \
167     if (audit_trail->isEnabled()) {                           \
168         audit_trail->invoke(__VA_ARGS__);                     \
169     }
170 
171 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \
172     GR_AUDIT_TRAIL_INVOKE_GUARD((audit_trail), pushFrame, framename);
173 
174 #define GR_AUDIT_TRAIL_RESET(audit_trail) \
175     //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, fullReset);
176 
177 #define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, proxy_id) \
178     GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, proxy_id);
179 
180 #define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \
181     GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op);
182 
183 #define GR_AUDIT_TRAIL_OP_RESULT_NEW(audit_trail, op) // Doesn't do anything now, one day...
184 
185 #endif
186