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