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