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 "GrRenderTargetProxy.h"
     14 #include "SkRect.h"
     15 #include "SkString.h"
     16 #include "SkTArray.h"
     17 #include "SkTHash.h"
     18 
     19 class GrOp;
     20 
     21 /*
     22  * GrAuditTrail collects a list of draw ops, detailed information about those ops, and can dump them
     23  * to json.
     24  *
     25  * Capturing this information is expensive and consumes a lot of memory, therefore it is important
     26  * to enable auditing only when required and disable it promptly. The AutoEnable class helps to
     27  * ensure that the audit trail is disabled in a timely fashion. Once the information has been dealt
     28  * with, be sure to call reset(), or the log will simply keep growing.
     29  */
     30 class GrAuditTrail {
     31 public:
     32     GrAuditTrail()
     33     : fClientID(kGrAuditTrailInvalidID)
     34     , fEnabled(false) {}
     35 
     36     class AutoEnable {
     37     public:
     38         AutoEnable(GrAuditTrail* auditTrail)
     39             : fAuditTrail(auditTrail) {
     40             SkASSERT(!fAuditTrail->isEnabled());
     41             fAuditTrail->setEnabled(true);
     42         }
     43 
     44         ~AutoEnable() {
     45             SkASSERT(fAuditTrail->isEnabled());
     46             fAuditTrail->setEnabled(false);
     47         }
     48 
     49     private:
     50         GrAuditTrail* fAuditTrail;
     51     };
     52 
     53     class AutoManageOpList {
     54     public:
     55         AutoManageOpList(GrAuditTrail* auditTrail)
     56                 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {}
     57 
     58         ~AutoManageOpList() { fAuditTrail->fullReset(); }
     59 
     60     private:
     61         AutoEnable fAutoEnable;
     62         GrAuditTrail* fAuditTrail;
     63     };
     64 
     65     class AutoCollectOps {
     66     public:
     67         AutoCollectOps(GrAuditTrail* auditTrail, int clientID)
     68                 : fAutoEnable(auditTrail), fAuditTrail(auditTrail) {
     69             fAuditTrail->setClientID(clientID);
     70         }
     71 
     72         ~AutoCollectOps() { fAuditTrail->setClientID(kGrAuditTrailInvalidID); }
     73 
     74     private:
     75         AutoEnable fAutoEnable;
     76         GrAuditTrail* fAuditTrail;
     77     };
     78 
     79     void pushFrame(const char* framename) {
     80         SkASSERT(fEnabled);
     81         fCurrentStackTrace.push_back(SkString(framename));
     82     }
     83 
     84     void addOp(const GrOp*, GrRenderTargetProxy::UniqueID proxyID);
     85 
     86     void opsCombined(const GrOp* consumer, const GrOp* consumed);
     87 
     88     // Because op combining is heavily dependent on sequence of draw calls, these calls will only
     89     // produce valid information for the given draw sequence which preceeded them. Specifically, ops
     90     // of future draw calls may combine with previous ops and thus would invalidate the json. What
     91     // this means is that for some sequence of draw calls N, the below toJson calls will only
     92     // produce JSON which reflects N draw calls. This JSON may or may not be accurate for N + 1 or
     93     // N - 1 draws depending on the actual combining algorithm used.
     94     SkString toJson(bool prettyPrint = false) const;
     95 
     96     // returns a json string of all of the ops associated with a given client id
     97     SkString toJson(int clientID, bool prettyPrint = false) const;
     98 
     99     bool isEnabled() { return fEnabled; }
    100     void setEnabled(bool enabled) { fEnabled = enabled; }
    101 
    102     void setClientID(int clientID) { fClientID = clientID; }
    103 
    104     // We could just return our internal bookkeeping struct if copying the data out becomes
    105     // a performance issue, but until then its nice to decouple
    106     struct OpInfo {
    107         struct Op {
    108             int    fClientID;
    109             SkRect fBounds;
    110         };
    111 
    112         SkRect                   fBounds;
    113         GrSurfaceProxy::UniqueID fProxyUniqueID;
    114         SkTArray<Op>             fOps;
    115     };
    116 
    117     void getBoundsByClientID(SkTArray<OpInfo>* outInfo, int clientID);
    118     void getBoundsByOpListID(OpInfo* outInfo, int opListID);
    119 
    120     void fullReset();
    121 
    122     static const int kGrAuditTrailInvalidID;
    123 
    124 private:
    125     // TODO if performance becomes an issue, we can move to using SkVarAlloc
    126     struct Op {
    127         SkString toJson() const;
    128         SkString fName;
    129         SkTArray<SkString> fStackTrace;
    130         SkRect fBounds;
    131         int fClientID;
    132         int fOpListID;
    133         int fChildID;
    134     };
    135     typedef SkTArray<std::unique_ptr<Op>, true> OpPool;
    136 
    137     typedef SkTArray<Op*> Ops;
    138 
    139     struct OpNode {
    140         OpNode(const GrSurfaceProxy::UniqueID& proxyID) : fProxyUniqueID(proxyID) { }
    141         SkString toJson() const;
    142 
    143         SkRect                         fBounds;
    144         Ops                            fChildren;
    145         const GrSurfaceProxy::UniqueID fProxyUniqueID;
    146     };
    147     typedef SkTArray<std::unique_ptr<OpNode>, true> OpList;
    148 
    149     void copyOutFromOpList(OpInfo* outOpInfo, int opListID);
    150 
    151     template <typename T>
    152     static void JsonifyTArray(SkString* json, const char* name, const T& array,
    153                               bool addComma);
    154 
    155     OpPool fOpPool;
    156     SkTHashMap<uint32_t, int> fIDLookup;
    157     SkTHashMap<int, Ops*> fClientIDLookup;
    158     OpList fOpList;
    159     SkTArray<SkString> fCurrentStackTrace;
    160 
    161     // The client can pass in an optional client ID which we will use to mark the ops
    162     int fClientID;
    163     bool fEnabled;
    164 };
    165 
    166 #define GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, invoke, ...) \
    167     if (audit_trail->isEnabled()) {                           \
    168         audit_trail->invoke(__VA_ARGS__);                     \
    169     }
    170 
    171 #define GR_AUDIT_TRAIL_AUTO_FRAME(audit_trail, framename) \
    172     GR_AUDIT_TRAIL_INVOKE_GUARD((audit_trail), pushFrame, framename);
    173 
    174 #define GR_AUDIT_TRAIL_RESET(audit_trail) \
    175     //GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, fullReset);
    176 
    177 #define GR_AUDIT_TRAIL_ADD_OP(audit_trail, op, proxy_id) \
    178     GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, addOp, op, proxy_id);
    179 
    180 #define GR_AUDIT_TRAIL_OPS_RESULT_COMBINED(audit_trail, combineWith, op) \
    181     GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail, opsCombined, combineWith, op);
    182 
    183 #define GR_AUDIT_TRAIL_OP_RESULT_NEW(audit_trail, op) // Doesn't do anything now, one day...
    184 
    185 #endif
    186