Home | History | Annotate | Download | only in private
      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