diff options
author | Chris Dalton <csmartdalton@google.com> | 2018-06-13 15:28:19 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-06-13 21:53:36 +0000 |
commit | 42c2115fc32e43c252284082a6e2473cef76e401 (patch) | |
tree | adddeb33229a57e95992c8cad6da609b3c9862a8 /src/gpu | |
parent | 527a297d6e2410277ff41c40dcbb56410d6a9118 (diff) |
ccpr: Initialize the atlas size more intelligently
Rather than always starting the atlas at 1024 x 1024, begin with the
first pow2 dimensions whose area is theoretically large enough to
contain the pending paths.
Bug: skia:
Change-Id: I263e77ff6a697e865f6b3b62b9df7002225f9544
Reviewed-on: https://skia-review.googlesource.com/133660
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/ccpr/GrCCAtlas.cpp | 46 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCAtlas.h | 25 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCClipPath.cpp | 15 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCDrawPathsOp.cpp | 47 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCDrawPathsOp.h | 24 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPerFlushResources.cpp | 32 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPerFlushResources.h | 34 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp | 54 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCoverageCountingPathRenderer.h | 2 |
9 files changed, 166 insertions, 113 deletions
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp index df84ed75a4..551b2a048e 100644 --- a/src/gpu/ccpr/GrCCAtlas.cpp +++ b/src/gpu/ccpr/GrCCAtlas.cpp @@ -21,9 +21,6 @@ #include "ccpr/GrCCPathParser.h" #include "ops/GrDrawOp.h" -static constexpr int kAtlasMinSize = 1024; -static constexpr int kPadding = 1; - class GrCCAtlas::Node { public: Node(std::unique_ptr<Node> previous, int l, int t, int r, int b) @@ -97,15 +94,27 @@ private: typedef GrDrawOp INHERITED; }; -GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minSize) - : fMaxAtlasSize(SkTMax(minSize, caps.maxPreferredRenderTargetSize())) { - // Caller should have cropped any paths to the destination render target instead of asking for - // an atlas larger than maxRenderTargetSize. - SkASSERT(fMaxAtlasSize <= caps.maxRenderTargetSize()); - int initialSize = GrNextPow2(minSize + kPadding); - initialSize = SkTMax(kAtlasMinSize, initialSize); - initialSize = SkTMin(initialSize, fMaxAtlasSize); - fHeight = fWidth = initialSize; +GrCCAtlas::GrCCAtlas(const Specs& specs) + : fMaxTextureSize(SkTMax(SkTMax(specs.fMinHeight, specs.fMinWidth), + specs.fMaxPreferredTextureSize)) { + SkASSERT(specs.fMaxPreferredTextureSize > 0); + + // Begin with the first pow2 dimensions whose area is theoretically large enough to contain the + // pending paths, favoring height over width if necessary. + int log2area = SkNextLog2(SkTMax(specs.fApproxNumPixels, 1)); + fHeight = 1 << ((log2area + 1) / 2); + fWidth = 1 << (log2area / 2); + + fWidth = SkTClamp(fWidth, specs.fMinTextureSize, specs.fMaxPreferredTextureSize); + fHeight = SkTClamp(fHeight, specs.fMinTextureSize, specs.fMaxPreferredTextureSize); + + if (fWidth < specs.fMinWidth || fHeight < specs.fMinHeight) { + // They want to stuff a particularly large path into the atlas. Just punt and go with their + // min width and height. The atlas will grow as needed. + fWidth = SkTMin(specs.fMinWidth + kPadding, fMaxTextureSize); + fHeight = SkTMin(specs.fMinHeight + kPadding, fMaxTextureSize); + } + fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight); } @@ -128,26 +137,26 @@ bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) { bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) { for (Node* node = fTopNode.get(); node; node = node->previous()) { - if (node->addRect(w, h, loc, fMaxAtlasSize)) { + if (node->addRect(w, h, loc, fMaxTextureSize)) { return true; } } // The rect didn't fit. Grow the atlas and try again. do { - if (fWidth == fMaxAtlasSize && fHeight == fMaxAtlasSize) { + if (fWidth == fMaxTextureSize && fHeight == fMaxTextureSize) { return false; } if (fHeight <= fWidth) { int top = fHeight; - fHeight = SkTMin(fHeight * 2, fMaxAtlasSize); + fHeight = SkTMin(fHeight * 2, fMaxTextureSize); fTopNode = skstd::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight); } else { int left = fWidth; - fWidth = SkTMin(fWidth * 2, fMaxAtlasSize); + fWidth = SkTMin(fWidth * 2, fMaxTextureSize); fTopNode = skstd::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight); } - } while (!fTopNode->addRect(w, h, loc, fMaxAtlasSize)); + } while (!fTopNode->addRect(w, h, loc, fMaxTextureSize)); return true; } @@ -156,6 +165,9 @@ sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFl sk_sp<const GrCCPathParser> parser) { SkASSERT(fCoverageCountBatchID); SkASSERT(!fTextureProxy); + // Caller should have cropped any paths to the destination render target instead of asking for + // an atlas larger than maxRenderTargetSize. + SkASSERT(fMaxTextureSize <= onFlushRP->caps()->maxRenderTargetSize()); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; diff --git a/src/gpu/ccpr/GrCCAtlas.h b/src/gpu/ccpr/GrCCAtlas.h index 184022ee96..b30bdbec6f 100644 --- a/src/gpu/ccpr/GrCCAtlas.h +++ b/src/gpu/ccpr/GrCCAtlas.h @@ -27,8 +27,22 @@ struct SkIPoint16; class GrCCAtlas { public: using CoverageCountBatchID = int; + static constexpr int kPadding = 1; // Amount of padding below and to the right of each path. - GrCCAtlas(const GrCaps&, int minSize); + // This struct encapsulates the minimum and desired requirements for an atlas, as well as an + // approximate number of pixels to help select a good initial size. + struct Specs { + int fMaxPreferredTextureSize = 0; + int fMinTextureSize = 0; + int fMinWidth = 0; // If there are 100 20x10 paths, this should be 20. + int fMinHeight = 0; // If there are 100 20x10 paths, this should be 10. + int fApproxNumPixels = 0; + + // Add space for a rect in the desired atlas specs. + void accountForSpace(int width, int height); + }; + + GrCCAtlas(const Specs&); ~GrCCAtlas(); bool addRect(int devWidth, int devHeight, SkIPoint16* loc); @@ -51,8 +65,7 @@ private: bool internalPlaceRect(int w, int h, SkIPoint16* loc); - const int fMaxAtlasSize; - + const int fMaxTextureSize; int fWidth, fHeight; std::unique_ptr<Node> fTopNode; SkISize fDrawBounds = {0, 0}; @@ -61,4 +74,10 @@ private: sk_sp<GrTextureProxy> fTextureProxy; }; +inline void GrCCAtlas::Specs::accountForSpace(int width, int height) { + fMinWidth = SkTMax(width, fMinWidth); + fMinHeight = SkTMax(height, fMinHeight); + fApproxNumPixels += (width + kPadding) * (height + kPadding); +} + #endif diff --git a/src/gpu/ccpr/GrCCClipPath.cpp b/src/gpu/ccpr/GrCCClipPath.cpp index 9b8a73752c..c98865765e 100644 --- a/src/gpu/ccpr/GrCCClipPath.cpp +++ b/src/gpu/ccpr/GrCCClipPath.cpp @@ -48,12 +48,23 @@ void GrCCClipPath::init(GrProxyProvider* proxyProvider, fAccessRect = accessRect; } +void GrCCClipPath::accountForOwnPath(GrCCPerFlushResourceSpecs* resourceSpecs) const { + SkASSERT(this->isInitialized()); + + ++resourceSpecs->fNumClipPaths; + resourceSpecs->fParsingPathStats.statPath(fDeviceSpacePath); + + SkIRect ibounds; + if (ibounds.intersect(fAccessRect, fPathDevIBounds)) { + resourceSpecs->fAtlasSpecs.accountForSpace(ibounds.width(), ibounds.height()); + } +} + void GrCCClipPath::renderPathInAtlas(GrCCPerFlushResources* resources, GrOnFlushResourceProvider* onFlushRP) { SkASSERT(this->isInitialized()); SkASSERT(!fHasAtlas); - fAtlas = resources->renderDeviceSpacePathInAtlas(*onFlushRP->caps(), fAccessRect, - fDeviceSpacePath, fPathDevIBounds, + fAtlas = resources->renderDeviceSpacePathInAtlas(fAccessRect, fDeviceSpacePath, fPathDevIBounds, &fAtlasOffsetX, &fAtlasOffsetY); SkDEBUGCODE(fHasAtlas = true); } diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.cpp b/src/gpu/ccpr/GrCCDrawPathsOp.cpp index 01913fa252..f29fca2f04 100644 --- a/src/gpu/ccpr/GrCCDrawPathsOp.cpp +++ b/src/gpu/ccpr/GrCCDrawPathsOp.cpp @@ -13,15 +13,6 @@ #include "ccpr/GrCCPerFlushResources.h" #include "ccpr/GrCoverageCountingPathRenderer.h" -GrCCDrawPathsOp* GrCCDrawPathsOp::Make(GrContext* context, - GrPaint&& paint, - const SkIRect& clipIBounds, - const SkMatrix& m, - const SkPath& path, - const SkRect& devBounds) { - return new GrCCDrawPathsOp(std::move(paint), clipIBounds, m, path, devBounds); -} - static bool has_coord_transforms(const GrPaint& paint) { GrFragmentProcessor::Iter iter(paint); while (const GrFragmentProcessor* fp = iter.next()) { @@ -32,13 +23,25 @@ static bool has_coord_transforms(const GrPaint& paint) { return false; } -GrCCDrawPathsOp::GrCCDrawPathsOp(GrPaint&& paint, const SkIRect& clipIBounds, const SkMatrix& m, - const SkPath& path, const SkRect& devBounds) +std::unique_ptr<GrCCDrawPathsOp> GrCCDrawPathsOp::Make(GrContext*, const SkIRect& clipIBounds, + const SkMatrix& m, const SkPath& path, + const SkRect& devBounds, GrPaint&& paint) { + SkIRect looseClippedIBounds; + devBounds.roundOut(&looseClippedIBounds); // GrCCPathParser might find slightly tighter bounds. + if (!looseClippedIBounds.intersect(clipIBounds)) { + return nullptr; + } + return std::unique_ptr<GrCCDrawPathsOp>( + new GrCCDrawPathsOp(looseClippedIBounds, m, path, devBounds, std::move(paint))); +} + +GrCCDrawPathsOp::GrCCDrawPathsOp(const SkIRect& looseClippedIBounds, const SkMatrix& m, + const SkPath& path, const SkRect& devBounds, GrPaint&& paint) : GrDrawOp(ClassID()) - , fSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint)) , fViewMatrixIfUsingLocalCoords(has_coord_transforms(paint) ? m : SkMatrix::I()) - , fDraws({clipIBounds, m, path, paint.getColor(), nullptr}) - , fProcessors(std::move(paint)) { + , fSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint)) + , fDraws({looseClippedIBounds, m, path, paint.getColor(), nullptr}) + , fProcessors(std::move(paint)) { // Paint must be moved after fetching its color above. SkDEBUGCODE(fBaseInstance = -1); // FIXME: intersect with clip bounds to (hopefully) improve batching. // (This is nontrivial due to assumptions in generating the octagon cover geometry.) @@ -90,13 +93,13 @@ void GrCCDrawPathsOp::wasRecorded(GrCCPerOpListPaths* owningPerOpListPaths) { fOwningPerOpListPaths = owningPerOpListPaths; } -int GrCCDrawPathsOp::countPaths(GrCCPathParser::PathStats* stats) const { - int numPaths = 0; +void GrCCDrawPathsOp::accountForOwnPaths(GrCCPerFlushResourceSpecs* resourceSpecs) const { for (const GrCCDrawPathsOp::SingleDraw& draw : fDraws) { - stats->statPath(draw.fPath); - ++numPaths; + ++resourceSpecs->fNumRenderedPaths; + resourceSpecs->fParsingPathStats.statPath(draw.fPath); + resourceSpecs->fAtlasSpecs.accountForSpace(draw.fLooseClippedIBounds.width(), + draw.fLooseClippedIBounds.height()); } - return numPaths; } void GrCCDrawPathsOp::setupResources(GrCCPerFlushResources* resources, @@ -112,9 +115,9 @@ void GrCCDrawPathsOp::setupResources(GrCCPerFlushResources* resources, // bounding boxes to generate an octagon that circumscribes the path. SkRect devBounds, devBounds45; int16_t atlasOffsetX, atlasOffsetY; - GrCCAtlas* atlas = resources->renderPathInAtlas(*onFlushRP->caps(), draw.fClipIBounds, - draw.fMatrix, draw.fPath, &devBounds, - &devBounds45, &atlasOffsetX, &atlasOffsetY); + GrCCAtlas* atlas = resources->renderPathInAtlas(draw.fLooseClippedIBounds, draw.fMatrix, + draw.fPath, &devBounds, &devBounds45, + &atlasOffsetX, &atlasOffsetY); if (!atlas) { SkDEBUGCODE(++fNumSkippedInstances); continue; diff --git a/src/gpu/ccpr/GrCCDrawPathsOp.h b/src/gpu/ccpr/GrCCDrawPathsOp.h index 303f52b529..b46039d3c8 100644 --- a/src/gpu/ccpr/GrCCDrawPathsOp.h +++ b/src/gpu/ccpr/GrCCDrawPathsOp.h @@ -9,11 +9,11 @@ #define GrCCDrawPathsOp_DEFINED #include "SkTInternalLList.h" -#include "ccpr/GrCCPathParser.h" #include "ccpr/GrCCPathProcessor.h" #include "ccpr/GrCCSTLList.h" #include "ops/GrDrawOp.h" +struct GrCCPerFlushResourceSpecs; class GrCCAtlas; class GrCCPerFlushResources; class GrCCPerOpListPaths; @@ -26,13 +26,9 @@ public: DEFINE_OP_CLASS_ID SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrCCDrawPathsOp); - static GrCCDrawPathsOp* Make(GrContext*, - GrPaint&&, - const SkIRect& clipIBounds, - const SkMatrix&, - const SkPath&, - const SkRect& devBounds); - + static std::unique_ptr<GrCCDrawPathsOp> Make(GrContext*, const SkIRect& clipIBounds, + const SkMatrix&, const SkPath&, + const SkRect& devBounds, GrPaint&&); ~GrCCDrawPathsOp() override; const char* name() const override { return "GrCCDrawOp"; } @@ -46,7 +42,7 @@ public: void onPrepare(GrOpFlushState*) override {} void wasRecorded(GrCCPerOpListPaths* owningPerOpListPaths); - int countPaths(GrCCPathParser::PathStats*) const; + void accountForOwnPaths(GrCCPerFlushResourceSpecs*) const; void setupResources(GrCCPerFlushResources*, GrOnFlushResourceProvider*); SkDEBUGCODE(int numSkippedInstances_debugOnly() const { return fNumSkippedInstances; }) @@ -55,8 +51,8 @@ public: private: friend class GrOpMemoryPool; - GrCCDrawPathsOp(GrPaint&&, const SkIRect& clipIBounds, const SkMatrix&, const SkPath&, - const SkRect& devBounds); + GrCCDrawPathsOp(const SkIRect& clippedDevIBounds, const SkMatrix&, const SkPath&, + const SkRect& devBounds, GrPaint&&); struct AtlasBatch { const GrCCAtlas* fAtlas; @@ -70,11 +66,11 @@ private: fAtlasBatches.push_back() = {atlas, endInstanceIdx}; } - const uint32_t fSRGBFlags; const SkMatrix fViewMatrixIfUsingLocalCoords; + const uint32_t fSRGBFlags; struct SingleDraw { - SkIRect fClipIBounds; + SkIRect fLooseClippedIBounds; SkMatrix fMatrix; SkPath fPath; GrColor fColor; @@ -84,8 +80,8 @@ private: GrCCSTLList<SingleDraw> fDraws; SkDEBUGCODE(int fNumDraws = 1); - GrProcessorSet fProcessors; GrCCPerOpListPaths* fOwningPerOpListPaths = nullptr; + GrProcessorSet fProcessors; int fBaseInstance; SkSTArray<1, AtlasBatch, true> fAtlasBatches; diff --git a/src/gpu/ccpr/GrCCPerFlushResources.cpp b/src/gpu/ccpr/GrCCPerFlushResources.cpp index 3f02ac75f6..a80d789f3f 100644 --- a/src/gpu/ccpr/GrCCPerFlushResources.cpp +++ b/src/gpu/ccpr/GrCCPerFlushResources.cpp @@ -14,13 +14,14 @@ using PathInstance = GrCCPathProcessor::Instance; GrCCPerFlushResources::GrCCPerFlushResources(GrOnFlushResourceProvider* onFlushRP, - int numPathDraws, int numClipPaths, - const GrCCPathParser::PathStats& pathStats) - : fPathParser(sk_make_sp<GrCCPathParser>(numPathDraws + numClipPaths, pathStats)) + const GrCCPerFlushResourceSpecs& specs) + : fPathParser(sk_make_sp<GrCCPathParser>(specs.fNumRenderedPaths + specs.fNumClipPaths, + specs.fParsingPathStats)) + , fAtlasSpecs(specs.fAtlasSpecs) , fIndexBuffer(GrCCPathProcessor::FindIndexBuffer(onFlushRP)) , fVertexBuffer(GrCCPathProcessor::FindVertexBuffer(onFlushRP)) , fInstanceBuffer(onFlushRP->makeBuffer(kVertex_GrBufferType, - numPathDraws * sizeof(PathInstance))) { + specs.fNumRenderedPaths * sizeof(PathInstance))) { if (!fIndexBuffer) { SkDebugf("WARNING: failed to allocate CCPR index buffer. No paths will be drawn.\n"); return; @@ -35,34 +36,31 @@ GrCCPerFlushResources::GrCCPerFlushResources(GrOnFlushResourceProvider* onFlushR } fPathInstanceData = static_cast<PathInstance*>(fInstanceBuffer->map()); SkASSERT(fPathInstanceData); - SkDEBUGCODE(fPathInstanceBufferCount = numPathDraws); + SkDEBUGCODE(fPathInstanceBufferCount = specs.fNumRenderedPaths); } -GrCCAtlas* GrCCPerFlushResources::renderPathInAtlas(const GrCaps& caps, const SkIRect& clipIBounds, - const SkMatrix& m, const SkPath& path, - SkRect* devBounds, SkRect* devBounds45, - int16_t* atlasOffsetX, int16_t* atlasOffsetY) { +GrCCAtlas* GrCCPerFlushResources::renderPathInAtlas(const SkIRect& clipIBounds, const SkMatrix& m, + const SkPath& path, SkRect* devBounds, + SkRect* devBounds45, int16_t* atlasOffsetX, + int16_t* atlasOffsetY) { SkASSERT(this->isMapped()); SkIRect devIBounds; fPathParser->parsePath(m, path, devBounds, devBounds45); devBounds->roundOut(&devIBounds); - return this->placeParsedPathInAtlas(caps, clipIBounds, devIBounds, atlasOffsetX, atlasOffsetY); + return this->placeParsedPathInAtlas(clipIBounds, devIBounds, atlasOffsetX, atlasOffsetY); } -GrCCAtlas* GrCCPerFlushResources::renderDeviceSpacePathInAtlas(const GrCaps& caps, - const SkIRect& clipIBounds, +GrCCAtlas* GrCCPerFlushResources::renderDeviceSpacePathInAtlas(const SkIRect& clipIBounds, const SkPath& devPath, const SkIRect& devPathIBounds, int16_t* atlasOffsetX, int16_t* atlasOffsetY) { SkASSERT(this->isMapped()); fPathParser->parseDeviceSpacePath(devPath); - return this->placeParsedPathInAtlas(caps, clipIBounds, devPathIBounds, atlasOffsetX, - atlasOffsetY); + return this->placeParsedPathInAtlas(clipIBounds, devPathIBounds, atlasOffsetX, atlasOffsetY); } -GrCCAtlas* GrCCPerFlushResources::placeParsedPathInAtlas(const GrCaps& caps, - const SkIRect& clipIBounds, +GrCCAtlas* GrCCPerFlushResources::placeParsedPathInAtlas(const SkIRect& clipIBounds, const SkIRect& pathIBounds, int16_t* atlasOffsetX, int16_t* atlasOffsetY) { @@ -87,7 +85,7 @@ GrCCAtlas* GrCCPerFlushResources::placeParsedPathInAtlas(const GrCaps& caps, auto coverageCountBatchID = fPathParser->closeCurrentBatch(); fAtlases.back().setCoverageCountBatchID(coverageCountBatchID); } - fAtlases.emplace_back(caps, SkTMax(w, h)); + fAtlases.emplace_back(fAtlasSpecs); SkAssertResult(fAtlases.back().addRect(w, h, &atlasLocation)); } diff --git a/src/gpu/ccpr/GrCCPerFlushResources.h b/src/gpu/ccpr/GrCCPerFlushResources.h index bc6b6edff3..14e3a1c667 100644 --- a/src/gpu/ccpr/GrCCPerFlushResources.h +++ b/src/gpu/ccpr/GrCCPerFlushResources.h @@ -15,23 +15,35 @@ #include "ccpr/GrCCPathProcessor.h" /** + * This struct encapsulates the minimum and desired requirements for the GPU resources required by + * CCPR in a given flush. + */ +struct GrCCPerFlushResourceSpecs { + int fNumRenderedPaths = 0; + int fNumClipPaths = 0; + GrCCPathParser::PathStats fParsingPathStats; + GrCCAtlas::Specs fAtlasSpecs; + + bool isEmpty() const { return 0 == fNumRenderedPaths + fNumClipPaths; } +}; + +/** * This class wraps all the GPU resources that CCPR builds at flush time. It is allocated in CCPR's * preFlush() method, and referenced by all the GrCCPerOpListPaths objects that are being flushed. * It is deleted in postFlush() once all the flushing GrCCPerOpListPaths objects are deleted. */ class GrCCPerFlushResources : public GrNonAtomicRef<GrCCPerFlushResources> { public: - GrCCPerFlushResources(GrOnFlushResourceProvider*, int numPathDraws, int numClipPaths, - const GrCCPathParser::PathStats&); + GrCCPerFlushResources(GrOnFlushResourceProvider*, const GrCCPerFlushResourceSpecs&); bool isMapped() const { return SkToBool(fPathInstanceData); } - GrCCAtlas* renderPathInAtlas(const GrCaps&, const SkIRect& clipIBounds, const SkMatrix&, - const SkPath&, SkRect* devBounds, SkRect* devBounds45, - int16_t* offsetX, int16_t* offsetY); - GrCCAtlas* renderDeviceSpacePathInAtlas(const GrCaps&, const SkIRect& clipIBounds, - const SkPath& devPath, const SkIRect& devPathIBounds, - int16_t* atlasOffsetX, int16_t* atlasOffsetY); + GrCCAtlas* renderPathInAtlas(const SkIRect& clipIBounds, const SkMatrix&, const SkPath&, + SkRect* devBounds, SkRect* devBounds45, int16_t* offsetX, + int16_t* offsetY); + GrCCAtlas* renderDeviceSpacePathInAtlas(const SkIRect& clipIBounds, const SkPath& devPath, + const SkIRect& devPathIBounds, int16_t* atlasOffsetX, + int16_t* atlasOffsetY); GrCCPathProcessor::Instance& appendDrawPathInstance() { SkASSERT(this->isMapped()); @@ -47,11 +59,11 @@ public: GrBuffer* instanceBuffer() const { SkASSERT(!this->isMapped()); return fInstanceBuffer.get(); } private: - GrCCAtlas* placeParsedPathInAtlas(const GrCaps&, const SkIRect& clipIBounds, - const SkIRect& pathIBounds, int16_t* atlasOffsetX, - int16_t* atlasOffsetY); + GrCCAtlas* placeParsedPathInAtlas(const SkIRect& clipIBounds, const SkIRect& pathIBounds, + int16_t* atlasOffsetX, int16_t* atlasOffsetY); const sk_sp<GrCCPathParser> fPathParser; + const GrCCAtlas::Specs fAtlasSpecs; sk_sp<const GrBuffer> fIndexBuffer; sk_sp<const GrBuffer> fVertexBuffer; diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index dcb9a588aa..9ad945cad7 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -68,15 +68,6 @@ GrCCPerOpListPaths* GrCoverageCountingPathRenderer::lookupPendingPaths(uint32_t return it->second.get(); } -void GrCoverageCountingPathRenderer::adoptAndRecordOp(GrCCDrawPathsOp* op, - const DrawPathArgs& args) { - GrRenderTargetContext* rtc = args.fRenderTargetContext; - if (uint32_t opListID = rtc->addDrawOp(*args.fClip, std::unique_ptr<GrDrawOp>(op))) { - // If the Op wasn't dropped or combined, give it a pointer to its owning GrCCPerOpListPaths. - op->wasRecorded(this->lookupPendingPaths(opListID)); - } -} - GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath( const CanDrawPathArgs& args) const { if (args.fShape->hasUnstyledKey() && !fDrawCachablePaths) { @@ -127,23 +118,34 @@ bool GrCoverageCountingPathRenderer::onDrawPath(const DrawPathArgs& args) { SkRect devBounds; args.fViewMatrix->mapRect(&devBounds, path.getBounds()); - GrCCDrawPathsOp* op; + std::unique_ptr<GrCCDrawPathsOp> op; if (SkTMax(devBounds.height(), devBounds.width()) > kPathCropThreshold) { // The path is too large. Crop it or analytic AA can run out of fp32 precision. SkPath croppedPath; path.transform(*args.fViewMatrix, &croppedPath); crop_path(croppedPath, clipIBounds, &croppedPath); - op = GrCCDrawPathsOp::Make(args.fContext, std::move(args.fPaint), clipIBounds, - SkMatrix::I(), croppedPath, croppedPath.getBounds()); + // FIXME: This breaks local coords: http://skbug.com/8003 + op = GrCCDrawPathsOp::Make(args.fContext, clipIBounds, SkMatrix::I(), croppedPath, + croppedPath.getBounds(), std::move(args.fPaint)); } else { - op = GrCCDrawPathsOp::Make(args.fContext, std::move(args.fPaint), clipIBounds, - *args.fViewMatrix, path, devBounds); + op = GrCCDrawPathsOp::Make(args.fContext, clipIBounds, *args.fViewMatrix, path, devBounds, + std::move(args.fPaint)); } - this->adoptAndRecordOp(op, args); + this->recordOp(std::move(op), args); return true; } +void GrCoverageCountingPathRenderer::recordOp(std::unique_ptr<GrCCDrawPathsOp> opHolder, + const DrawPathArgs& args) { + if (GrCCDrawPathsOp* op = opHolder.get()) { + GrRenderTargetContext* rtc = args.fRenderTargetContext; + if (uint32_t opListID = rtc->addDrawOp(*args.fClip, std::move(opHolder))) { + op->wasRecorded(this->lookupPendingPaths(opListID)); + } + } +} + std::unique_ptr<GrFragmentProcessor> GrCoverageCountingPathRenderer::makeClipProcessor( GrProxyProvider* proxyProvider, uint32_t opListID, const SkPath& deviceSpacePath, const SkIRect& accessRect, @@ -186,11 +188,13 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush return; // Nothing to draw. } + GrCCPerFlushResourceSpecs resourceSpecs; + int maxPreferredRTSize = onFlushRP->caps()->maxPreferredRenderTargetSize(); + resourceSpecs.fAtlasSpecs.fMaxPreferredTextureSize = maxPreferredRTSize; + resourceSpecs.fAtlasSpecs.fMinTextureSize = SkTMin(1024, maxPreferredRTSize); + // Move the per-opList paths that are about to be flushed from fPendingPaths to fFlushingPaths, - // and count up the paths about to be flushed so we can preallocate buffers. - int numPathDraws = 0; - int numClipPaths = 0; - GrCCPathParser::PathStats flushingPathStats; + // and count them up so we can preallocate buffers. fFlushingPaths.reserve(numOpListIDs); for (int i = 0; i < numOpListIDs; ++i) { auto iter = fPendingPaths.find(opListIDs[i]); @@ -202,20 +206,18 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush fPendingPaths.erase(iter); for (const GrCCDrawPathsOp* op : fFlushingPaths.back()->fDrawOps) { - numPathDraws += op->countPaths(&flushingPathStats); + op->accountForOwnPaths(&resourceSpecs); } for (const auto& clipsIter : fFlushingPaths.back()->fClipPaths) { - flushingPathStats.statPath(clipsIter.second.deviceSpacePath()); + clipsIter.second.accountForOwnPath(&resourceSpecs); } - numClipPaths += fFlushingPaths.back()->fClipPaths.size(); } - if (0 == numPathDraws + numClipPaths) { + if (resourceSpecs.isEmpty()) { return; // Nothing to draw. } - auto resources = sk_make_sp<GrCCPerFlushResources>(onFlushRP, numPathDraws, numClipPaths, - flushingPathStats); + auto resources = sk_make_sp<GrCCPerFlushResources>(onFlushRP, resourceSpecs); if (!resources->isMapped()) { return; // Some allocation failed. } @@ -231,7 +233,7 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush clipsIter.second.renderPathInAtlas(resources.get(), onFlushRP); } } - SkASSERT(resources->nextPathInstanceIdx() == numPathDraws - numSkippedPaths); + SkASSERT(resources->nextPathInstanceIdx() == resourceSpecs.fNumRenderedPaths - numSkippedPaths); // Allocate the atlases and create instance buffers to draw them. if (!resources->finalize(onFlushRP, atlasDraws)) { diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h index 4032bd51d5..63e52a972e 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h @@ -75,7 +75,7 @@ private: : fDrawCachablePaths(drawCachablePaths) {} GrCCPerOpListPaths* lookupPendingPaths(uint32_t opListID); - void adoptAndRecordOp(GrCCDrawPathsOp*, const DrawPathArgs&); + void recordOp(std::unique_ptr<GrCCDrawPathsOp>, const DrawPathArgs&); // fPendingPaths holds the GrCCPerOpListPaths objects that have already been created, but not // flushed, and those that are still being created. All GrCCPerOpListPaths objects will first |