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 "SkRect.h" 13 #include "SkString.h" 14 #include "SkTArray.h" 15 16 /* 17 * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them 18 * to json. 19 * 20 * Capturing this information is expensive and consumes a lot of memory, therefore it is important 21 * to enable auditing only when required and disable it promptly. The AutoEnable class helps to 22 * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt 23 * with, be sure to call reset(), or the log will simply keep growing. 24 */ 25 class GrAuditTrail { 26 public: GrAuditTrail()27 GrAuditTrail() 28 : fEnabled(false) 29 , fUniqueID(0) {} 30 31 class AutoFrame { 32 public: AutoFrame(GrAuditTrail * auditTrail,const char * name)33 AutoFrame(GrAuditTrail* auditTrail, const char* name) 34 : fAuditTrail(auditTrail) { 35 if (fAuditTrail->fEnabled) { 36 fAuditTrail->pushFrame(name); 37 } 38 } 39 ~AutoFrame()40 ~AutoFrame() { 41 if (fAuditTrail->fEnabled) { 42 fAuditTrail->popFrame(); 43 } 44 } 45 46 private: 47 GrAuditTrail* fAuditTrail; 48 }; 49 50 class AutoEnable { 51 public: AutoEnable(GrAuditTrail * auditTrail)52 AutoEnable(GrAuditTrail* auditTrail) 53 : fAuditTrail(auditTrail) { 54 SkASSERT(!fAuditTrail->isEnabled()); 55 fAuditTrail->setEnabled(true); 56 } 57 ~AutoEnable()58 ~AutoEnable() { 59 SkASSERT(fAuditTrail->isEnabled()); 60 fAuditTrail->setEnabled(false); 61 } 62 63 private: 64 GrAuditTrail* fAuditTrail; 65 }; 66 pushFrame(const char * name)67 void pushFrame(const char* name) { 68 SkASSERT(fEnabled); 69 Frame* frame = new Frame; 70 if (fStack.empty()) { 71 fFrames.emplace_back(frame); 72 } else { 73 fStack.back()->fChildren.emplace_back(frame); 74 } 75 76 frame->fUniqueID = fUniqueID++; 77 frame->fName = name; 78 fStack.push_back(frame); 79 } 80 popFrame()81 void popFrame() { 82 SkASSERT(fEnabled); 83 fStack.pop_back(); 84 } 85 addBatch(const char * name,const SkRect & bounds)86 void addBatch(const char* name, const SkRect& bounds) { 87 SkASSERT(fEnabled && !fStack.empty()); 88 Batch* batch = new Batch; 89 fStack.back()->fChildren.emplace_back(batch); 90 batch->fName = name; 91 batch->fBounds = bounds; 92 } 93 94 SkString toJson(bool prettyPrint = false) const; 95 isEnabled()96 bool isEnabled() { return fEnabled; } setEnabled(bool enabled)97 void setEnabled(bool enabled) { fEnabled = enabled; } 98 reset()99 void reset() { SkASSERT(fEnabled && fStack.empty()); fFrames.reset(); } 100 101 private: 102 // TODO if performance becomes an issue, we can move to using SkVarAlloc 103 struct Event { ~EventEvent104 virtual ~Event() {} 105 virtual SkString toJson() const=0; 106 107 const char* fName; 108 uint64_t fUniqueID; 109 }; 110 111 typedef SkTArray<SkAutoTDelete<Event>, true> FrameArray; 112 struct Frame : public Event { 113 SkString toJson() const override; 114 FrameArray fChildren; 115 }; 116 117 struct Batch : public Event { 118 SkString toJson() const override; 119 SkRect fBounds; 120 }; 121 122 static void JsonifyTArray(SkString* json, const char* name, const FrameArray& array, 123 bool addComma); 124 125 bool fEnabled; 126 FrameArray fFrames; 127 SkTArray<Frame*> fStack; 128 uint64_t fUniqueID; 129 }; 130 131 #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \ 132 if (audit_trail->isEnabled()) { \ 133 audit_trail->invoke(__VA_ARGS__); \ 134 } 135 136 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \ 137 GrAuditTrail::AutoFrame SK_MACRO_APPEND_LINE(auto_frame)(audit_trail, framename); 138 139 #define GR_AUDIT_TRAIL_RESET(audit_trail) \ 140 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, reset); 141 142 #define GR_AUDIT_TRAIL_ADDBATCH(audit_trail, batchname, bounds) \ 143 GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addBatch, batchname, bounds); 144 145 #endif 146