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