diff --git a/include/private/GrAuditTrail.h b/include/private/GrAuditTrail.h index bcd85e221c..53f44f2173 100644 --- a/include/private/GrAuditTrail.h +++ b/include/private/GrAuditTrail.h @@ -9,6 +9,7 @@ #define GrAuditTrail_DEFINED #include "GrConfig.h" +#include "SkRect.h" #include "SkString.h" #include "SkTArray.h" @@ -18,11 +19,18 @@ */ class GrAuditTrail { public: - void addOp(SkString name) { + void addOp(const SkString& name) { SkASSERT(GR_BATCH_DEBUGGING_OUTPUT); fOps.push_back().fName = name; } + void addBatch(const SkString& name, const SkRect& bounds) { + SkASSERT(GR_BATCH_DEBUGGING_OUTPUT); + Op::Batch& batch = fOps.back().fBatches.push_back(); + batch.fName = name; + batch.fBounds = bounds; + } + SkString toJson() const; void reset() { SkASSERT(GR_BATCH_DEBUGGING_OUTPUT); fOps.reset(); } @@ -30,7 +38,14 @@ public: private: struct Op { SkString toJson() const; + struct Batch { + SkString toJson() const; + SkString fName; + SkRect fBounds; + }; + SkString fName; + SkTArray fBatches; }; SkTArray fOps; @@ -41,11 +56,13 @@ private: invoke(__VA_ARGS__); \ } - #define GR_AUDIT_TRAIL_ADDOP(audit_trail, opname) \ GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail->addOp, opname); #define GR_AUDIT_TRAIL_RESET(audit_trail) \ GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail->reset); +#define GR_AUDIT_TRAIL_ADDBATCH(audit_trail, batchname, bounds) \ + GR_AUDIT_TRAIL_INVOKE_GUARD(audit_trail->addBatch, SkString(batchname), bounds); + #endif diff --git a/src/gpu/GrAuditTrail.cpp b/src/gpu/GrAuditTrail.cpp index 5a62a35794..aa87af2cbd 100644 --- a/src/gpu/GrAuditTrail.cpp +++ b/src/gpu/GrAuditTrail.cpp @@ -7,26 +7,116 @@ #include "GrAuditTrail.h" -SkString GrAuditTrail::toJson() const { - SkString json; - json.append("{\n"); - json.append("\"Ops\": [\n"); - for (int i = 0; i < fOps.count(); i++) { - json.append(fOps[i].toJson()); - if (i < fOps.count() - 1) { - json.append(",\n"); +template +static void jsonify_tarray(SkString* json, const SkTArray& array) { + for (int i = 0; i < array.count(); i++) { + json->append(array[i].toJson()); + if (i < array.count() - 1) { + json->append(","); } } - json.append("]\n"); - json.append("}\n"); - return json; +} + +// This will pretty print a very small subset of json +// The parsing rules are straightforward, aside from the fact that we do not want an extra newline +// before ',' and after '}', so we have a comma exception rule. +class PrettyPrintJson { +public: + SkString prettify(const SkString& json) { + fPrettyJson.reset(); + fTabCount = 0; + fFreshLine = false; + fCommaException = false; + for (size_t i = 0; i < json.size(); i++) { + if ('[' == json[i] || '{' == json[i]) { + this->newline(); + this->appendChar(json[i]); + fTabCount++; + this->newline(); + } else if (']' == json[i] || '}' == json[i]) { + fTabCount--; + this->newline(); + this->appendChar(json[i]); + fCommaException = true; + } else if (',' == json[i]) { + this->appendChar(json[i]); + this->newline(); + } else { + this->appendChar(json[i]); + } + } + return fPrettyJson; + } +private: + void appendChar(char appendee) { + if (fCommaException && ',' != appendee) { + this->newline(); + } + this->tab(); + fPrettyJson += appendee; + fFreshLine = false; + fCommaException = false; + } + + void tab() { + if (fFreshLine) { + for (int i = 0; i < fTabCount; i++) { + fPrettyJson += '\t'; + } + } + } + + void newline() { + if (!fFreshLine) { + fFreshLine = true; + fPrettyJson += '\n'; + } + } + + SkString fPrettyJson; + int fTabCount; + bool fFreshLine; + bool fCommaException; +}; + +static SkString pretty_print_json(SkString json) { + class PrettyPrintJson prettyPrintJson; + return prettyPrintJson.prettify(json); +} + +SkString GrAuditTrail::toJson() const { + SkString json; + json.append("{"); + json.append("\"Ops\": ["); + jsonify_tarray(&json, fOps); + json.append("]"); + json.append("}"); + + // TODO if this becomes a performance issue we should make pretty print configurable + return pretty_print_json(json); } SkString GrAuditTrail::Op::toJson() const { SkString json; - json.append("{\n"); - json.appendf("\"Name\": \"%s\"\n", fName.c_str()); - json.append("}\n"); + json.append("{"); + json.appendf("\"Name\": \"%s\",", fName.c_str()); + json.append("\"Batches\": ["); + jsonify_tarray(&json, fBatches); + json.append("]"); + json.append("}"); return json; } +SkString GrAuditTrail::Op::Batch::toJson() const { + SkString json; + json.append("{"); + json.appendf("\"Name\": \"%s\",", fName.c_str()); + json.append("\"Bounds\": {"); + json.appendf("\"Left\": %f,", fBounds.fLeft); + json.appendf("\"Right\": %f,", fBounds.fRight); + json.appendf("\"Top\": %f,", fBounds.fTop); + json.appendf("\"Bottom\": %f", fBounds.fBottom); + json.append("}"); + json.append("}"); + return json; +} diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp index 3918ce2a21..bae4cabaae 100644 --- a/src/gpu/GrDrawTarget.cpp +++ b/src/gpu/GrDrawTarget.cpp @@ -8,6 +8,7 @@ #include "GrDrawTarget.h" +#include "GrAuditTrail.h" #include "GrCaps.h" #include "GrGpu.h" #include "GrPath.h" @@ -20,6 +21,8 @@ #include "GrTexture.h" #include "GrVertexBuffer.h" +#include "SkStrokeRec.h" + #include "batches/GrClearBatch.h" #include "batches/GrCopySurfaceBatch.h" #include "batches/GrDiscardBatch.h" @@ -28,17 +31,16 @@ #include "batches/GrRectBatchFactory.h" #include "batches/GrStencilPathBatch.h" -#include "SkStrokeRec.h" - //////////////////////////////////////////////////////////////////////////////// // Experimentally we have found that most batching occurs within the first 10 comparisons. static const int kDefaultMaxBatchLookback = 10; GrDrawTarget::GrDrawTarget(GrRenderTarget* rt, GrGpu* gpu, GrResourceProvider* resourceProvider, - const Options& options) + GrAuditTrail* auditTrail, const Options& options) : fGpu(SkRef(gpu)) , fResourceProvider(resourceProvider) + , fAuditTrail(auditTrail) , fFlags(0) , fRenderTarget(rt) { // TODO: Stop extracting the context (currently needed by GrClipMaskManager) @@ -466,7 +468,7 @@ void GrDrawTarget::recordBatch(GrBatch* batch) { // 1) check every draw // 2) intersect with something // 3) find a 'blocker' - + GR_AUDIT_TRAIL_ADDBATCH(fAuditTrail, batch->name(), batch->bounds()); GrBATCH_INFO("Re-Recording (%s, B%u)\n" "\tBounds LRTB (%f, %f, %f, %f)\n", batch->name(), diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h index 7117ad3fe8..72ab46e934 100644 --- a/src/gpu/GrDrawTarget.h +++ b/src/gpu/GrDrawTarget.h @@ -34,6 +34,7 @@ //#define ENABLE_MDB 1 +class GrAuditTrail; class GrBatch; class GrClip; class GrCaps; @@ -50,7 +51,7 @@ public: int fMaxBatchLookback; }; - GrDrawTarget(GrRenderTarget*, GrGpu*, GrResourceProvider*, const Options&); + GrDrawTarget(GrRenderTarget*, GrGpu*, GrResourceProvider*, GrAuditTrail*, const Options&); ~GrDrawTarget() override; @@ -288,6 +289,7 @@ private: GrContext* fContext; GrGpu* fGpu; GrResourceProvider* fResourceProvider; + GrAuditTrail* fAuditTrail; SkDEBUGCODE(int fDebugID;) uint32_t fFlags; diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp index 266aa478ed..f69625837b 100644 --- a/src/gpu/GrDrawingManager.cpp +++ b/src/gpu/GrDrawingManager.cpp @@ -114,6 +114,13 @@ void GrDrawingManager::flush() { fDrawTargets.reset(); #endif + // Clear batch debugging output + if (GR_BATCH_DEBUGGING_OUTPUT) { + SkDebugf("%s\n", fContext->getAuditTrail()->toJson().c_str()); + // TODO This currently crashes because not all ops are accounted for + //GR_AUDIT_TRAIL_RESET(fContext->getAuditTrail()); + } + fFlushState.reset(); fFlushing = false; } @@ -162,7 +169,7 @@ GrDrawTarget* GrDrawingManager::newDrawTarget(GrRenderTarget* rt) { #endif GrDrawTarget* dt = new GrDrawTarget(rt, fContext->getGpu(), fContext->resourceProvider(), - fOptionsForDrawTargets); + fContext->getAuditTrail(), fOptionsForDrawTargets); *fDrawTargets.append() = dt; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index e33ea4477c..233825d489 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -411,6 +411,7 @@ static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkP void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { ASSERT_SINGLE_OWNER + GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext); CHECK_FOR_ANNOTATION(paint); CHECK_SHOULD_DRAW(draw); @@ -1784,12 +1785,6 @@ void SkGpuDevice::flush() { ASSERT_SINGLE_OWNER DO_DEFERRED_CLEAR(); fRenderTarget->prepareForExternalIO(); - - // Clear batch debugging output - if (GR_BATCH_DEBUGGING_OUTPUT) { - SkDebugf("%s\n", fContext->getAuditTrail()->toJson().c_str()); - GR_AUDIT_TRAIL_RESET(fContext->getAuditTrail()); - } } ///////////////////////////////////////////////////////////////////////////////