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 "SkRect.h" 14 #include "SkString.h" 15 #include "SkTArray.h" 16 #include "SkTHash.h" 17 18 class GrOp; 19 20 /* 21 * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them 22 * to json. 23 * 24 * Capturing this information is expensive and consumes a lot of memory, therefore it is important 25 * to enable auditing only when required and disable it promptly. The AutoEnable class helps to 26 * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt 27 * with, be sure to call reset(), or the log will simply keep growing. 28 */ 29 class GrAuditTrail { 30 public: 31 GrAuditTrail() 32 : fClientID(kGrAuditTrailInvalidID) 33 , fEnabled(false) {} 34 35 class AutoEnable { 36 public: 37 AutoEnable(GrAuditTrail* auditTrail) 38 : fAuditTrail(auditTrail) { 39 SkASSERT(!fAuditTrail->isEnabled()); 40 fAuditTrail->setEnabled(true); 41 } 42 43 ~AutoEnable() { 44 SkASSERT(fAuditTrail->isEnabled()); 45 fAuditTrail->setEnabled(false); 46 } 47 48 private: 49 GrAuditTrail* fAuditTrail; 50 }; 51 52 class AutoManageOpList { 53 public: 54 AutoManageOpList(GrAuditTrail* auditTrail) 55 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {} 56 57 ~AutoManageOpList() { fAuditTrail->fullReset(); } 58 59 private: 60 AutoEnable fAutoEnable; 61 GrAuditTrail* fAuditTrail; 62 }; 63 64 class AutoCollectOps { 65 public: 66 AutoCollectOps(GrAuditTrail* auditTrail, int clientID) 67 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) { 68 fAuditTrail->setClientID(clientID); 69 } 70 71 ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); } 72 73 private: 74 AutoEnable fAutoEnable; 75 GrAuditTrail* fAuditTrail; 76 }; 77 78 void pushFrame(const char* framename) { 79 SkASSERT(fEnabled); 80 fCurrentStackTrace.push_back(SkString(framename)); 81 } 82 83 void addOp(const GrOp*, GrGpuResource::UniqueID renderTargetID); 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 SkString toJson(bool prettyPrint = false) const; 94 95 // returns a json string of all of the ops associated with a given client id 96 SkString toJson(int clientID, bool prettyPrint = false) const; 97 98 bool isEnabled() { return fEnabled; } 99 void setEnabled(bool enabled) { fEnabled = enabled; } 100 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 SkRect fBounds; 107 // TODO: switch over to GrSurfaceProxy::UniqueID 108 GrGpuResource::UniqueID fRenderTargetUniqueID; 109 struct Op { 110 int fClientID; 111 SkRect fBounds; 112 }; 113 SkTArray<Op> fOps; 114 }; 115 116 void getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID); 117 void getBoundsByOpListID(OpInfo* outInfo, int opListID); 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 SkString toJson() const; 127 SkString fName; 128 SkTArray<SkString> fStackTrace; 129 SkRect fBounds; 130 int fClientID; 131 int fOpListID; 132 int fChildID; 133 }; 134 typedef SkTArray<std::unique_ptr<Op>, true> OpPool; 135 136 typedef SkTArray<Op*> Ops; 137 138 struct OpNode { 139 OpNode(const GrGpuResource::UniqueID& id) : fRenderTargetUniqueID(id) {} 140 SkString toJson() const; 141 SkRect fBounds; 142 Ops fChildren; 143 const GrGpuResource::UniqueID fRenderTargetUniqueID; 144 }; 145 typedef SkTArray<std::unique_ptr<OpNode>, true> OpList; 146 147 void copyOutFromOpList(OpInfo* outOpInfo, int opListID); 148 149 template <typename T> 150 static void JsonifyTArray(SkString* json, const char* name, const T& array, 151 bool addComma); 152 153 OpPool fOpPool; 154 SkTHashMap<uint32_t, int> fIDLookup; 155 SkTHashMap<int, Ops*> fClientIDLookup; 156 OpList fOpList; 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()) { \ 166 audit_trail->invoke(__VA_ARGS__); \ 167 } 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, rt_id) \ 176 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, rt_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 #define GR_AUDIT_TRAIL_OP_RESULT_NEW(audit_trail, op) // Doesn't do anything now, one day... 182 183 #endif 184