127a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt/*
227a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt * Copyright 2016 Google Inc.
327a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt *
427a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt * Use of this source code is governed by a BSD-style license that can be
527a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt * found in the LICENSE file.
627a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt */
727a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
827a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt#ifndef GrAuditTrail_DEFINED
927a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt#define GrAuditTrail_DEFINED
1027a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
115651ee6376dc3271ea8f4fc91b037c8f361c3cfajoshualitt#include "GrConfig.h"
12294870ff119b89fc902773643b054f14e5d1f554Robert Phillips#include "GrGpuResource.h"
13086cee12deaf9a9f46bbd2e52173e0e4fc4df311joshualitt#include "SkRect.h"
1427a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt#include "SkString.h"
1527a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt#include "SkTArray.h"
1618d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt#include "SkTHash.h"
1718d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
1825a880960a9a689a745a01071ecba3fe494b5940Brian Salomonclass GrOp;
1927a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
2027a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt/*
2127a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them
2227a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt * to json.
23c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas *
24c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas * Capturing this information is expensive and consumes a lot of memory, therefore it is important
25c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas * to enable auditing only when required and disable it promptly. The AutoEnable class helps to
26c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt
27c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas * with, be sure to call reset(), or the log will simply keep growing.
2827a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt */
2927a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualittclass GrAuditTrail {
3027a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualittpublic:
31c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    GrAuditTrail()
32b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    : fClientID(kGrAuditTrailInvalidID)
33b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    , fEnabled(false) {}
3487a721b2465c9ccfa191ce9f5012f92be7731fbcjoshualitt
35c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    class AutoEnable {
36c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    public:
37c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas        AutoEnable(GrAuditTrail* auditTrail)
38c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas            : fAuditTrail(auditTrail) {
39c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas            SkASSERT(!fAuditTrail->isEnabled());
40c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas            fAuditTrail->setEnabled(true);
41c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas        }
42c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas
43c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas        ~AutoEnable() {
44c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas            SkASSERT(fAuditTrail->isEnabled());
45c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas            fAuditTrail->setEnabled(false);
46c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas        }
47c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas
48c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    private:
49c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas        GrAuditTrail* fAuditTrail;
50c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    };
51c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas
5242ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    class AutoManageOpList {
5318d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt    public:
5442ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        AutoManageOpList(GrAuditTrail* auditTrail)
5542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon                : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {}
5618d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
5742ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        ~AutoManageOpList() { fAuditTrail->fullReset(); }
5818d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
5918d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt    private:
6018d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt        AutoEnable fAutoEnable;
6118d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt        GrAuditTrail* fAuditTrail;
6218d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt    };
6318d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
6442ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    class AutoCollectOps {
65b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    public:
6642ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        AutoCollectOps(GrAuditTrail* auditTrail, int clientID)
6742ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon                : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {
68b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt            fAuditTrail->setClientID(clientID);
6987a721b2465c9ccfa191ce9f5012f92be7731fbcjoshualitt        }
7087a721b2465c9ccfa191ce9f5012f92be7731fbcjoshualitt
7142ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); }
7227a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
73b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    private:
74b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        AutoEnable fAutoEnable;
75b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        GrAuditTrail* fAuditTrail;
76b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    };
7787a721b2465c9ccfa191ce9f5012f92be7731fbcjoshualitt
78f55c3644850409c9410051c7a7f18af8d65bf990joshualitt    void pushFrame(const char* framename) {
79f55c3644850409c9410051c7a7f18af8d65bf990joshualitt        SkASSERT(fEnabled);
80f55c3644850409c9410051c7a7f18af8d65bf990joshualitt        fCurrentStackTrace.push_back(SkString(framename));
81f55c3644850409c9410051c7a7f18af8d65bf990joshualitt    }
82f55c3644850409c9410051c7a7f18af8d65bf990joshualitt
8369868af68403bd12aee040187347426affe41accBrian Salomon    void addOp(const GrOp*, GrGpuResource::UniqueID renderTargetID);
84086cee12deaf9a9f46bbd2e52173e0e4fc4df311joshualitt
8542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    void opsCombined(const GrOp* consumer, const GrOp* consumed);
8618d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
8742ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // Because op combining is heavily dependent on sequence of draw calls, these calls will only
8842ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // produce valid information for the given draw sequence which preceeded them. Specifically, ops
8942ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // of future draw calls may combine with previous ops and thus would invalidate the json. What
9042ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // this means is that for some sequence of draw calls N, the below toJson calls will only
9142ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // produce JSON which reflects N draw calls. This JSON may or may not be accurate for N + 1 or
9242ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // N - 1 draws depending on the actual combining algorithm used.
93b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    SkString toJson(bool prettyPrint = false) const;
94b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt
9542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // returns a json string of all of the ops associated with a given client id
96b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    SkString toJson(int clientID, bool prettyPrint = false) const;
9727a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
98c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    bool isEnabled() { return fEnabled; }
99c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    void setEnabled(bool enabled) { fEnabled = enabled; }
100c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas
101b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    void setClientID(int clientID) { fClientID = clientID; }
10218d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
10310d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt    // We could just return our internal bookkeeping struct if copying the data out becomes
10410d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt    // a performance issue, but until then its nice to decouple
10542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    struct OpInfo {
10642ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        SkRect fBounds;
107294870ff119b89fc902773643b054f14e5d1f554Robert Phillips        // TODO: switch over to GrSurfaceProxy::UniqueID
108294870ff119b89fc902773643b054f14e5d1f554Robert Phillips        GrGpuResource::UniqueID fRenderTargetUniqueID;
10942ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        struct Op {
11010d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt            int fClientID;
11110d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt            SkRect fBounds;
11210d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt        };
11342ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        SkTArray<Op> fOps;
11410d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt    };
11510d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt
11642ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    void getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID);
11742ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    void getBoundsByOpListID(OpInfo* outInfo, int opListID);
11810d8fc29bc1605c134e98f5b58c2efb73cef6073joshualitt
119df3f2b0948507d20e72b16869f1b2bb1abdf4b40joshualitt    void fullReset();
12018d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
121b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    static const int kGrAuditTrailInvalidID;
12227a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
12327a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualittprivate:
12411fae87d39811882e3e99b4abc72c9713a38da55joshualitt    // TODO if performance becomes an issue, we can move to using SkVarAlloc
12542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    struct Op {
126b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        SkString toJson() const;
127b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        SkString fName;
128f55c3644850409c9410051c7a7f18af8d65bf990joshualitt        SkTArray<SkString> fStackTrace;
129b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        SkRect fBounds;
130b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        int fClientID;
13142ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        int fOpListID;
132b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        int fChildID;
13327a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt    };
13442ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    typedef SkTArray<std::unique_ptr<Op>, true> OpPool;
13527a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
13642ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    typedef SkTArray<Op*> Ops;
13711fae87d39811882e3e99b4abc72c9713a38da55joshualitt
13842ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    struct OpNode {
13942ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        OpNode(const GrGpuResource::UniqueID& id) : fRenderTargetUniqueID(id) {}
140b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt        SkString toJson() const;
141294870ff119b89fc902773643b054f14e5d1f554Robert Phillips        SkRect                         fBounds;
14242ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon        Ops fChildren;
143294870ff119b89fc902773643b054f14e5d1f554Robert Phillips        const GrGpuResource::UniqueID  fRenderTargetUniqueID;
14411fae87d39811882e3e99b4abc72c9713a38da55joshualitt    };
14542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    typedef SkTArray<std::unique_ptr<OpNode>, true> OpList;
14611fae87d39811882e3e99b4abc72c9713a38da55joshualitt
14742ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    void copyOutFromOpList(OpInfo* outOpInfo, int opListID);
14846b301d2222b60dd5ab495b917dea163e8be94efjoshualitt
14918d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt    template <typename T>
15018d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt    static void JsonifyTArray(SkString* json, const char* name, const T& array,
151adab5a2a4b2ae4d7fa832093fe81a640e848746cjoshualitt                              bool addComma);
1526bd5284415bd983b0628c4941dff5def40018f5abungeman
15342ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    OpPool fOpPool;
154b0666ad3a9e99ce1a6e6d9ea69ff9f1ddbe74594joshualitt    SkTHashMap<uint32_t, int> fIDLookup;
15542ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    SkTHashMap<int, Ops*> fClientIDLookup;
15642ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    OpList fOpList;
157f55c3644850409c9410051c7a7f18af8d65bf990joshualitt    SkTArray<SkString> fCurrentStackTrace;
158b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt
15942ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    // The client can pass in an optional client ID which we will use to mark the ops
160b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    int fClientID;
161b95c772d45efc98f0159fa65c7aa06314cecb9dejoshualitt    bool fEnabled;
16227a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt};
16327a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt
164c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas#define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \
165c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas    if (audit_trail->isEnabled()) {                           \
166c85d9fbc0adacc9acb9faa3fe107652f0d76760aethannicholas        audit_trail->invoke(__VA_ARGS__);                     \
1675651ee6376dc3271ea8f4fc91b037c8f361c3cfajoshualitt    }
1685651ee6376dc3271ea8f4fc91b037c8f361c3cfajoshualitt
16987a721b2465c9ccfa191ce9f5012f92be7731fbcjoshualitt#define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \
170f55c3644850409c9410051c7a7f18af8d65bf990joshualitt    GR_AUDIT_TRAIL_INVOKE_GUARD((audit_trail), pushFrame, framename);
1715651ee6376dc3271ea8f4fc91b037c8f361c3cfajoshualitt
1725651ee6376dc3271ea8f4fc91b037c8f361c3cfajoshualitt#define GR_AUDIT_TRAIL_RESET(audit_trail) \
173f55c3644850409c9410051c7a7f18af8d65bf990joshualitt    //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, fullReset);
1745651ee6376dc3271ea8f4fc91b037c8f361c3cfajoshualitt
17569868af68403bd12aee040187347426affe41accBrian Salomon#define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, rt_id) \
17669868af68403bd12aee040187347426affe41accBrian Salomon    GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, rt_id);
177086cee12deaf9a9f46bbd2e52173e0e4fc4df311joshualitt
17842ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon#define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \
17942ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon    GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op);
18018d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
18142ad83ac194c4c1848fef95e6cdcad83729e6ecfBrian Salomon#define GR_AUDIT_TRAIL_OP_RESULT_NEW(audit_trail, op) // Doesn't do anything now, one day...
18218d6b75829ac5d90050ca4da4f99292c14ff06f0joshualitt
18327a48dc0cddad7f3531dcf0d39d290e7233e3e76joshualitt#endif
184