• 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 "include/gpu/GrTypes.h"
12 
13 #if SK_GPU_V1
14 
15 #include "include/core/SkRect.h"
16 #include "include/core/SkString.h"
17 #include "include/gpu/GrConfig.h"
18 #include "include/private/SkTArray.h"
19 #include "include/private/SkTHash.h"
20 #include "src/gpu/GrRenderTargetProxy.h"
21 
22 class GrOp;
23 class SkJSONWriter;
24 
25 /*
26  * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them
27  * to json.
28  *
29  * Capturing this information is expensive and consumes a lot of memory, therefore it is important
30  * to enable auditing only when required and disable it promptly. The AutoEnable class helps to
31  * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt
32  * with, be sure to call reset(), or the log will simply keep growing.
33  */
34 class GrAuditTrail {
35 public:
GrAuditTrail()36     GrAuditTrail() : fClientID(kGrAuditTrailInvalidID), fEnabled(false) {}
37 
38     class AutoEnable {
39     public:
AutoEnable(GrAuditTrail * auditTrail)40         AutoEnable(GrAuditTrail* auditTrail)
41             : fAuditTrail(auditTrail) {
42             SkASSERT(!fAuditTrail->isEnabled());
43             fAuditTrail->setEnabled(true);
44         }
45 
~AutoEnable()46         ~AutoEnable() {
47             SkASSERT(fAuditTrail->isEnabled());
48             fAuditTrail->setEnabled(false);
49         }
50 
51     private:
52         GrAuditTrail* fAuditTrail;
53     };
54 
55     class AutoManageOpsTask {
56     public:
AutoManageOpsTask(GrAuditTrail * auditTrail)57         AutoManageOpsTask(GrAuditTrail* auditTrail)
58                 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {}
59 
~AutoManageOpsTask()60         ~AutoManageOpsTask() { fAuditTrail->fullReset(); }
61 
62     private:
63         AutoEnable fAutoEnable;
64         GrAuditTrail* fAuditTrail;
65     };
66 
67     class AutoCollectOps {
68     public:
AutoCollectOps(GrAuditTrail * auditTrail,int clientID)69         AutoCollectOps(GrAuditTrail* auditTrail, int clientID)
70                 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {
71             fAuditTrail->setClientID(clientID);
72         }
73 
~AutoCollectOps()74         ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); }
75 
76     private:
77         AutoEnable fAutoEnable;
78         GrAuditTrail* fAuditTrail;
79     };
80 
pushFrame(const char * framename)81     void pushFrame(const char* framename) {
82         SkASSERT(fEnabled);
83         fCurrentStackTrace.push_back(SkString(framename));
84     }
85 
86     void addOp(const GrOp*, 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     void toJson(SkJSONWriter& writer) const;
97 
98     // returns a json string of all of the ops associated with a given client id
99     void toJson(SkJSONWriter& writer, int clientID) const;
100 
isEnabled()101     bool isEnabled() { return fEnabled; }
setEnabled(bool enabled)102     void setEnabled(bool enabled) { fEnabled = enabled; }
103 
setClientID(int clientID)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     struct OpInfo {
109         struct Op {
110             int    fClientID;
111             SkRect fBounds;
112         };
113 
114         SkRect                   fBounds;
115         GrSurfaceProxy::UniqueID fProxyUniqueID;
116         SkTArray<Op>             fOps;
117     };
118 
119     void getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID);
120     void getBoundsByOpsTaskID(OpInfo* outInfo, int opsTaskID);
121 
122     void fullReset();
123 
124     static const int kGrAuditTrailInvalidID;
125 
126 private:
127     // TODO if performance becomes an issue, we can move to using SkVarAlloc
128     struct Op {
129         void toJson(SkJSONWriter& writer) const;
130         SkString fName;
131         SkTArray<SkString> fStackTrace;
132         SkRect fBounds;
133         int fClientID;
134         int fOpsTaskID;
135         int fChildID;
136     };
137     typedef SkTArray<std::unique_ptr<Op>, true> OpPool;
138 
139     typedef SkTArray<Op*> Ops;
140 
141     struct OpNode {
OpNodeOpNode142         OpNode(const GrSurfaceProxy::UniqueID& proxyID) : fProxyUniqueID(proxyID) { }
143         void toJson(SkJSONWriter& writer) const;
144 
145         SkRect                         fBounds;
146         Ops                            fChildren;
147         const GrSurfaceProxy::UniqueID fProxyUniqueID;
148     };
149     typedef SkTArray<std::unique_ptr<OpNode>, true> OpsTask;
150 
151     void copyOutFromOpsTask(OpInfo* outOpInfo, int opsTask);
152 
153     template <typename T>
154     static void JsonifyTArray(SkJSONWriter& writer, const char* name, const T& array);
155 
156     OpPool fOpPool;
157     SkTHashMap<uint32_t, int> fIDLookup;
158     SkTHashMap<int, Ops*> fClientIDLookup;
159     OpsTask fOpsTask;
160     SkTArray<SkString> fCurrentStackTrace;
161 
162     // The client can pass in an optional client ID which we will use to mark the ops
163     int fClientID;
164     bool fEnabled;
165 };
166 
167 #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \
168         if (audit_trail->isEnabled()) audit_trail->invoke(__VA_ARGS__)
169 
170 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \
171     GR_AUDIT_TRAIL_INVOKE_GUARD((audit_trail), pushFrame, framename)
172 
173 #define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, proxy_id) \
174     GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, proxy_id)
175 
176 #define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \
177     GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op)
178 
179 #else // SK_GPU_V1
180 
181 class GrAuditTrail {
182 };
183 
184 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename)
185 #define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, proxy_id)
186 #define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op)
187 
188 #endif // SK_GPU_V1
189 #endif // GrAuditTrail_DEFINED
190