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