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