diff options
author | Chris Dalton <csmartdalton@google.com> | 2018-01-18 12:24:50 -0700 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-01-18 19:46:48 +0000 |
commit | 9ca27849d8259e4b35243094bdca969612efba2f (patch) | |
tree | 614ca332891670f012963d42645ef8ba5af56d69 /src | |
parent | a583b813b9f1e2904d6f9f6cb487b9e477d2bde4 (diff) |
Extract a GrCCPathParser class that is decoupled from atlas ops
Allows coverage counts ultimately to be drawn either to an atlas or
directly to the framebuffer.
Bug: skia:
Change-Id: I6cc07fce562c223381b89586d19ae98298bafe4d
Reviewed-on: https://skia-review.googlesource.com/96083
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/ccpr/GrCCAtlas.cpp | 48 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCAtlas.h | 15 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCCoverageOp.h | 175 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCGeometry.h | 5 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPathParser.cpp (renamed from src/gpu/ccpr/GrCCCoverageOp.cpp) | 284 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCCPathParser.h | 124 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp | 57 | ||||
-rw-r--r-- | src/gpu/ccpr/GrCoverageCountingPathRenderer.h | 9 |
8 files changed, 358 insertions, 359 deletions
diff --git a/src/gpu/ccpr/GrCCAtlas.cpp b/src/gpu/ccpr/GrCCAtlas.cpp index 055382cf9b..5ef39f85cb 100644 --- a/src/gpu/ccpr/GrCCAtlas.cpp +++ b/src/gpu/ccpr/GrCCAtlas.cpp @@ -15,6 +15,7 @@ #include "SkMakeUnique.h" #include "SkMathPriv.h" #include "ccpr/GrCCCoverageProcessor.h" +#include "ccpr/GrCCPathParser.h" #include "ops/GrDrawOp.h" class GrCCAtlas::Node { @@ -41,6 +42,40 @@ private: GrRectanizerSkyline fRectanizer; }; +class GrCCAtlas::DrawCoverageCountOp : public GrDrawOp { +public: + DEFINE_OP_CLASS_ID + + DrawCoverageCountOp(sk_sp<const GrCCPathParser> parser, CoverageCountBatchID batchID, + const SkISize& drawBounds) + : INHERITED(ClassID()) + , fParser(std::move(parser)) + , fBatchID(batchID) + , fDrawBounds(drawBounds) { + this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()), + GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo); + } + + // GrDrawOp interface. + const char* name() const override { return "GrCCAtlas::DrawCoverageCountOp"; } + FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } + RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*, + GrPixelConfigIsClamped) override { return RequiresDstTexture::kNo; } + bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; } + void onPrepare(GrOpFlushState*) override {} + void onExecute(GrOpFlushState* flushState) override { + fParser->drawCoverageCount(flushState, fBatchID, + SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height())); + } + +private: + const sk_sp<const GrCCPathParser> fParser; + const CoverageCountBatchID fBatchID; + const SkISize fDrawBounds; + + typedef GrDrawOp INHERITED; +}; + GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minWidth, int minHeight) : fMaxAtlasSize(caps.maxRenderTargetSize()), fDrawBounds{0, 0} { SkASSERT(fMaxAtlasSize <= caps.maxTextureSize()); @@ -55,7 +90,8 @@ GrCCAtlas::GrCCAtlas(const GrCaps& caps, int minWidth, int minHeight) GrCCAtlas::~GrCCAtlas() {} bool GrCCAtlas::addRect(int w, int h, SkIPoint16* loc) { - // This can't be called anymore once finalize() has been called. + // This can't be called anymore once setCoverageCountBatchID() has been called. + SkASSERT(!fCoverageCountBatchID); SkASSERT(!fTextureProxy); if (!this->internalPlaceRect(w, h, loc)) { @@ -96,8 +132,9 @@ bool GrCCAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) { return true; } -sk_sp<GrRenderTargetContext> GrCCAtlas::finalize( - GrOnFlushResourceProvider* onFlushRP, std::unique_ptr<GrDrawOp> atlasOp) { +sk_sp<GrRenderTargetContext> GrCCAtlas::finalize(GrOnFlushResourceProvider* onFlushRP, + sk_sp<const GrCCPathParser> parser) { + SkASSERT(fCoverageCountBatchID); SkASSERT(!fTextureProxy); GrSurfaceDesc desc; @@ -113,7 +150,10 @@ sk_sp<GrRenderTargetContext> GrCCAtlas::finalize( SkIRect clearRect = SkIRect::MakeSize(fDrawBounds); rtc->clear(&clearRect, 0, GrRenderTargetContext::CanClearFullscreen::kYes); - rtc->addDrawOp(GrNoClip(), std::move(atlasOp)); + + auto op = skstd::make_unique<DrawCoverageCountOp>(std::move(parser), fCoverageCountBatchID, + fDrawBounds); + rtc->addDrawOp(GrNoClip(), std::move(op)); fTextureProxy = sk_ref_sp(rtc->asTextureProxy()); return rtc; diff --git a/src/gpu/ccpr/GrCCAtlas.h b/src/gpu/ccpr/GrCCAtlas.h index bf17c05f8c..cac82af894 100644 --- a/src/gpu/ccpr/GrCCAtlas.h +++ b/src/gpu/ccpr/GrCCAtlas.h @@ -12,6 +12,7 @@ #include "SkSize.h" class GrCaps; +class GrCCPathParser; class GrDrawOp; class GrOnFlushResourceProvider; class GrRenderTargetContext; @@ -27,19 +28,28 @@ class GrCCAtlas { public: static constexpr int kMinSize = 1024; + using CoverageCountBatchID = int; + GrCCAtlas(const GrCaps&, int minWidth, int minHeight); ~GrCCAtlas(); bool addRect(int devWidth, int devHeight, SkIPoint16* loc); const SkISize& drawBounds() { return fDrawBounds; } - sk_sp<GrRenderTargetContext> SK_WARN_UNUSED_RESULT - finalize(GrOnFlushResourceProvider*, std::unique_ptr<GrDrawOp> atlasOp); + void setCoverageCountBatchID(CoverageCountBatchID batchID) { + SkASSERT(!fCoverageCountBatchID); + SkASSERT(!fTextureProxy); + fCoverageCountBatchID = batchID; + } + + sk_sp<GrRenderTargetContext> SK_WARN_UNUSED_RESULT finalize(GrOnFlushResourceProvider*, + sk_sp<const GrCCPathParser>); GrTextureProxy* textureProxy() const { return fTextureProxy.get(); } private: class Node; + class DrawCoverageCountOp; bool internalPlaceRect(int w, int h, SkIPoint16* loc); @@ -50,6 +60,7 @@ private: SkISize fDrawBounds; std::unique_ptr<Node> fTopNode; + CoverageCountBatchID fCoverageCountBatchID SkDEBUGCODE(= 0); sk_sp<GrTextureProxy> fTextureProxy; }; diff --git a/src/gpu/ccpr/GrCCCoverageOp.h b/src/gpu/ccpr/GrCCCoverageOp.h deleted file mode 100644 index 3ae2b4d4a9..0000000000 --- a/src/gpu/ccpr/GrCCCoverageOp.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrCCCoverageOp_DEFINED -#define GrCCCoverageOp_DEFINED - -#include "GrMesh.h" -#include "SkRect.h" -#include "SkRefCnt.h" -#include "ccpr/GrCCCoverageProcessor.h" -#include "ccpr/GrCCGeometry.h" -#include "ops/GrDrawOp.h" - -class GrCCCoverageOp; -class GrOnFlushResourceProvider; -class SkMatrix; -class SkPath; - -/** - * This class produces GrCCCoverageOps that render coverage count masks and atlases. A path is - * added to the current op in two steps: - * - * 1) parsePath(ScissorMode, viewMatrix, path, &devBounds, &devBounds45); - * - * <client decides where to put the mask within an atlas, if wanted> - * - * 2) saveParsedPath(offsetX, offsetY, clipBounds); - * - * The client can flush the currently saved paths to a GrCCCoverageOp by calling emitOp, and - * retrieve all emitted ops after calling finalize(). - */ -class GrCCCoverageOpsBuilder { -public: - // Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified - // as an int because these values get used directly as indices into arrays.) - enum class ScissorMode : int { kNonScissored = 0, kScissored = 1 }; - static constexpr int kNumScissorModes = 2; - - GrCCCoverageOpsBuilder(int maxTotalPaths, int maxPathPoints, int numSkPoints, int numSkVerbs) - : fPathsInfo(maxTotalPaths) - , fLocalDevPtsBuffer(maxPathPoints + 1) // Overallocate by one point to accomodate for - // overflow with Sk4f. (See parsePath.) - , fGeometry(numSkPoints, numSkVerbs) - , fTallies{PrimitiveTallies(), PrimitiveTallies()} - , fScissorBatches(maxTotalPaths) {} - - ~GrCCCoverageOpsBuilder() { - // Enforce the contract that the client always calls saveParsedPath or discardParsedPath. - SkASSERT(!fParsingPath); - } - - // Parses an SkPath into a temporary staging area. The path will not yet be included in the next - // Op unless there is a matching call to saveParsedPath. The user must complement this with a - // following call to either saveParsedPath or discardParsedPath. - // - // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space. - // | 1 1 | - void parsePath(const SkMatrix&, const SkPath&, SkRect* devBounds, SkRect* devBounds45); - - // Parses a device-space SkPath into a temporary staging area. The path will not yet be included - // in the next Op unless there is a matching call to saveParsedPath. The user must complement - // this with a following call to either saveParsedPath or discardParsedPath. - void parseDeviceSpacePath(const SkPath&); - - // Commits the currently-parsed path from staging to the next Op, and specifies whether the mask - // should be rendered with a scissor clip in effect. Accepts an optional post-device-space - // translate for placement in an atlas. - void saveParsedPath(ScissorMode, const SkIRect& clippedDevIBounds, int16_t atlasOffsetX, - int16_t atlasOffsetY); - void discardParsedPath(); - - // Flushes all currently-saved paths internally to a GrCCCoverageOp. - // - // NOTE: if there is a parsed path in the staging area, it will not be included. But the client - // may still call saveParsedPath to include it in a future Op. - void emitOp(SkISize drawBounds); - - // Builds GPU buffers and returns the list of GrCCCoverageOps as specified by calls to emitOp. - bool finalize(GrOnFlushResourceProvider*, SkTArray<std::unique_ptr<GrCCCoverageOp>>*); - -private: - using PrimitiveTallies = GrCCGeometry::PrimitiveTallies; - - // Every kBeginPath verb has a corresponding PathInfo entry. - struct PathInfo { - ScissorMode fScissorMode; - int16_t fAtlasOffsetX, fAtlasOffsetY; - std::unique_ptr<GrCCCoverageOp> fTerminatingOp; - }; - - // Every PathInfo with a mode of kScissored has a corresponding ScissorBatch. - struct ScissorBatch { - PrimitiveTallies fInstanceCounts; - SkIRect fScissor; - }; - - void parsePath(const SkPath&, const SkPoint* deviceSpacePts); - void endContourIfNeeded(bool insideContour); - - // Staging area for the path being parsed. - SkDEBUGCODE(int fParsingPath = false); - int fCurrPathPointsIdx; - int fCurrPathVerbsIdx; - PrimitiveTallies fCurrPathTallies; - - SkSTArray<32, PathInfo, true> fPathsInfo; - - const SkAutoSTArray<32, SkPoint> fLocalDevPtsBuffer; - GrCCGeometry fGeometry; - - PrimitiveTallies fTallies[kNumScissorModes]; - SkTArray<ScissorBatch, true> fScissorBatches; - - std::unique_ptr<GrCCCoverageOp> fTerminatingOp; - - friend class GrCCCoverageOp; // For ScissorBatch. -}; - -/** - * This Op renders coverage count masks and atlases. Create it using GrCCCoverageOpsBuilder. - */ -class GrCCCoverageOp : public GrDrawOp { -public: - DEFINE_OP_CLASS_ID - - // GrDrawOp interface. - const char* name() const override { return "GrCCCoverageOp"; } - FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } - RequiresDstTexture finalize(const GrCaps&, const GrAppliedClip*, - GrPixelConfigIsClamped) override { - return RequiresDstTexture::kNo; - } - bool onCombineIfPossible(GrOp* other, const GrCaps& caps) override { return false; } - void onPrepare(GrOpFlushState*) override {} - void onExecute(GrOpFlushState*) override; - -private: - static constexpr int kNumScissorModes = GrCCCoverageOpsBuilder::kNumScissorModes; - using PrimitiveTallies = GrCCGeometry::PrimitiveTallies; - using ScissorBatch = GrCCCoverageOpsBuilder::ScissorBatch; - - GrCCCoverageOp(SkTArray<ScissorBatch, true>&& scissorBatches, const SkISize& drawBounds) - : INHERITED(ClassID()) - , fScissorBatches(std::move(scissorBatches)) - , fDrawBounds(drawBounds) { - this->setBounds(SkRect::MakeIWH(fDrawBounds.width(), fDrawBounds.height()), - GrOp::HasAABloat::kNo, GrOp::IsZeroArea::kNo); - } - - void setInstanceBuffer(sk_sp<GrBuffer> instanceBuffer, - const PrimitiveTallies baseInstances[kNumScissorModes], - const PrimitiveTallies endInstances[kNumScissorModes]); - - void drawMaskPrimitives(GrOpFlushState*, const GrPipeline&, GrCCCoverageProcessor::RenderPass, - int PrimitiveTallies::*instanceType) const; - - sk_sp<GrBuffer> fInstanceBuffer; - PrimitiveTallies fBaseInstances[kNumScissorModes]; - PrimitiveTallies fInstanceCounts[kNumScissorModes]; - const SkTArray<ScissorBatch, true> fScissorBatches; - const SkISize fDrawBounds; - - mutable SkTArray<GrMesh> fMeshesScratchBuffer; - mutable SkTArray<GrPipeline::DynamicState, true> fDynamicStatesScratchBuffer; - - friend class GrCCCoverageOpsBuilder; - - typedef GrDrawOp INHERITED; -}; - -#endif diff --git a/src/gpu/ccpr/GrCCGeometry.h b/src/gpu/ccpr/GrCCGeometry.h index 57cd998150..b50dd015eb 100644 --- a/src/gpu/ccpr/GrCCGeometry.h +++ b/src/gpu/ccpr/GrCCGeometry.h @@ -43,6 +43,7 @@ public: void operator+=(const PrimitiveTallies&); PrimitiveTallies operator-(const PrimitiveTallies&) const; + bool operator==(const PrimitiveTallies&); }; GrCCGeometry(int numSkPoints = 0, int numSkVerbs = 0) @@ -138,4 +139,8 @@ inline GrCCGeometry::PrimitiveTallies::operator-(const PrimitiveTallies& b) cons fCubics - b.fCubics}; } +inline bool GrCCGeometry::PrimitiveTallies::operator==(const PrimitiveTallies& b) { + return fTriangles == b.fTriangles && fQuadratics == b.fQuadratics && fCubics == b.fCubics; +} + #endif diff --git a/src/gpu/ccpr/GrCCCoverageOp.cpp b/src/gpu/ccpr/GrCCPathParser.cpp index 92403b0cbc..03fb3d924b 100644 --- a/src/gpu/ccpr/GrCCCoverageOp.cpp +++ b/src/gpu/ccpr/GrCCPathParser.cpp @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -#include "GrCCCoverageOp.h" +#include "GrCCPathParser.h" #include "GrCaps.h" #include "GrGpuCommandBuffer.h" @@ -20,8 +20,23 @@ using TriangleInstance = GrCCCoverageProcessor::TriangleInstance; using CubicInstance = GrCCCoverageProcessor::CubicInstance; -void GrCCCoverageOpsBuilder::parsePath(const SkMatrix& m, const SkPath& path, SkRect* devBounds, - SkRect* devBounds45) { +GrCCPathParser::GrCCPathParser(int maxTotalPaths, int maxPathPoints, int numSkPoints, + int numSkVerbs) + : fLocalDevPtsBuffer(maxPathPoints + 1) // Overallocate by one point to accomodate for + // overflow with Sk4f. (See parsePath.) + , fGeometry(numSkPoints, numSkVerbs) + , fPathsInfo(maxTotalPaths) + , fScissorSubBatches(maxTotalPaths) + , fTotalPrimitiveCounts{PrimitiveTallies(), PrimitiveTallies()} { + // Batches decide what to draw by looking where the previous one ended. Define initial batches + // that "end" at the beginning of the data. These will not be drawn, but will only be be read by + // the first actual batch. + fScissorSubBatches.push_back() = {PrimitiveTallies(), SkIRect::MakeEmpty()}; + fCoverageCountBatches.push_back() = {PrimitiveTallies(), fScissorSubBatches.count()}; +} + +void GrCCPathParser::parsePath(const SkMatrix& m, const SkPath& path, SkRect* devBounds, + SkRect* devBounds45) { const SkPoint* pts = SkPathPriv::PointData(path); int numPts = path.countPoints(); SkASSERT(numPts + 1 <= fLocalDevPtsBuffer.count()); @@ -77,18 +92,19 @@ void GrCCCoverageOpsBuilder::parsePath(const SkMatrix& m, const SkPath& path, Sk this->parsePath(path, fLocalDevPtsBuffer.get()); } -void GrCCCoverageOpsBuilder::parseDeviceSpacePath(const SkPath& deviceSpacePath) { +void GrCCPathParser::parseDeviceSpacePath(const SkPath& deviceSpacePath) { this->parsePath(deviceSpacePath, SkPathPriv::PointData(deviceSpacePath)); } -void GrCCCoverageOpsBuilder::parsePath(const SkPath& path, const SkPoint* deviceSpacePts) { - SkASSERT(!fParsingPath); +void GrCCPathParser::parsePath(const SkPath& path, const SkPoint* deviceSpacePts) { + SkASSERT(!fInstanceBuffer); // Can't call after finalize(). + SkASSERT(!fParsingPath); // Call saveParsedPath() or discardParsedPath() for the last one first. SkDEBUGCODE(fParsingPath = true); SkASSERT(path.isEmpty() || deviceSpacePts); fCurrPathPointsIdx = fGeometry.points().count(); fCurrPathVerbsIdx = fGeometry.verbs().count(); - fCurrPathTallies = PrimitiveTallies(); + fCurrPathPrimitiveCounts = PrimitiveTallies(); fGeometry.beginPath(); @@ -134,45 +150,46 @@ void GrCCCoverageOpsBuilder::parsePath(const SkPath& path, const SkPoint* device this->endContourIfNeeded(insideContour); } -void GrCCCoverageOpsBuilder::endContourIfNeeded(bool insideContour) { +void GrCCPathParser::endContourIfNeeded(bool insideContour) { if (insideContour) { - fCurrPathTallies += fGeometry.endContour(); + fCurrPathPrimitiveCounts += fGeometry.endContour(); } } -void GrCCCoverageOpsBuilder::saveParsedPath(ScissorMode scissorMode, - const SkIRect& clippedDevIBounds, int16_t atlasOffsetX, - int16_t atlasOffsetY) { +void GrCCPathParser::saveParsedPath(ScissorMode scissorMode, const SkIRect& clippedDevIBounds, + int16_t atlasOffsetX, int16_t atlasOffsetY) { SkASSERT(fParsingPath); - fPathsInfo.push_back() = {scissorMode, atlasOffsetX, atlasOffsetY, std::move(fTerminatingOp)}; - - fTallies[(int)scissorMode] += fCurrPathTallies; + fPathsInfo.push_back() = {scissorMode, atlasOffsetX, atlasOffsetY}; + fTotalPrimitiveCounts[(int)scissorMode] += fCurrPathPrimitiveCounts; if (ScissorMode::kScissored == scissorMode) { - fScissorBatches.push_back() = {fCurrPathTallies, - clippedDevIBounds.makeOffset(atlasOffsetX, atlasOffsetY)}; + fScissorSubBatches.push_back() = {fTotalPrimitiveCounts[(int)ScissorMode::kScissored], + clippedDevIBounds.makeOffset(atlasOffsetX, atlasOffsetY)}; } SkDEBUGCODE(fParsingPath = false); } -void GrCCCoverageOpsBuilder::discardParsedPath() { +void GrCCPathParser::discardParsedPath() { SkASSERT(fParsingPath); - - // The code will still work whether or not the below assertion is true. It is just unlikely that - // the caller would want this, and probably indicative of of a mistake. (Why emit an - // intermediate Op (to switch to a new atlas?), just to then throw the path away?) - SkASSERT(!fTerminatingOp); - fGeometry.resize_back(fCurrPathPointsIdx, fCurrPathVerbsIdx); SkDEBUGCODE(fParsingPath = false); } -void GrCCCoverageOpsBuilder::emitOp(SkISize drawBounds) { - SkASSERT(!fTerminatingOp); - fTerminatingOp.reset(new GrCCCoverageOp(std::move(fScissorBatches), drawBounds)); - SkASSERT(fScissorBatches.empty()); +GrCCPathParser::CoverageCountBatchID GrCCPathParser::closeCurrentBatch() { + SkASSERT(!fInstanceBuffer); + SkASSERT(!fCoverageCountBatches.empty()); + + int maxMeshes = 1 + fScissorSubBatches.count() - + fCoverageCountBatches.back().fEndScissorSubBatchIdx; + fMaxMeshesPerDraw = SkTMax(fMaxMeshesPerDraw, maxMeshes); + + fCoverageCountBatches.push_back() = { + fTotalPrimitiveCounts[(int)ScissorMode::kNonScissored], + fScissorSubBatches.count() + }; + return fCoverageCountBatches.count() - 1; } // Emits a contour's triangle fan. @@ -196,8 +213,8 @@ static TriangleInstance* emit_recursive_fan(const SkTArray<SkPoint, true>& pts, return out; } - const int32_t oneThirdCount = indexCount / 3; - const int32_t twoThirdsCount = (2 * indexCount) / 3; + int32_t oneThirdCount = indexCount / 3; + int32_t twoThirdsCount = (2 * indexCount) / 3; out++->set(pts[indices[firstIndex]], pts[indices[firstIndex + oneThirdCount]], pts[indices[firstIndex + twoThirdsCount]], atlasOffset); @@ -215,49 +232,50 @@ static TriangleInstance* emit_recursive_fan(const SkTArray<SkPoint, true>& pts, return out; } -bool GrCCCoverageOpsBuilder::finalize(GrOnFlushResourceProvider* onFlushRP, - SkTArray<std::unique_ptr<GrCCCoverageOp>>* ops) { - SkASSERT(!fParsingPath); +bool GrCCPathParser::finalize(GrOnFlushResourceProvider* onFlushRP) { + SkASSERT(!fParsingPath); // Call saveParsedPath() or discardParsedPath(). + SkASSERT(fCoverageCountBatches.back().fEndNonScissorIndices == // Call closeCurrentBatch(). + fTotalPrimitiveCounts[(int)ScissorMode::kNonScissored]); + SkASSERT(fCoverageCountBatches.back().fEndScissorSubBatchIdx == fScissorSubBatches.count()); - // Here we build a single instance buffer to share with every draw call from every CoverageOP we - // plan to produce. + // Here we build a single instance buffer to share with every internal batch. // - // CoverageOps process 4 different types of primitives (triangles, quadratics, serpentines, - // loops), and each primitive type is further divided into instances that require a scissor and - // those that don't. This leaves us with 8 independent instance arrays to build for the GPU. + // CCPR processs 3 different types of primitives: triangles, quadratics, cubics. Each primitive + // type is further divided into instances that require a scissor and those that don't. This + // leaves us with 3*2 = 6 independent instance arrays to build for the GPU. // - // Rather than placing each instance array in its own GPU buffer, we allocate a single + // Rather than place each instance array in its own GPU buffer, we allocate a single // megabuffer and lay them all out side-by-side. We can offset the "baseInstance" parameter in // our draw calls to direct the GPU to the applicable elements within a given array. // - // We already know how big to make each of the 8 arrays from fTallies[kNumScissorModes], so - // layout is straightforward. - PrimitiveTallies baseInstances[kNumScissorModes]; - - // Start with triangles and quadratics. They both view the instance buffer as an array of - // TriangleInstance[], so we can just start at zero and lay them out one after the other. - baseInstances[0].fTriangles = 0; - baseInstances[1].fTriangles = baseInstances[0].fTriangles + fTallies[0].fTriangles; - baseInstances[0].fQuadratics = baseInstances[1].fTriangles + fTallies[1].fTriangles; - baseInstances[1].fQuadratics = baseInstances[0].fQuadratics + fTallies[0].fQuadratics; - int triEndIdx = baseInstances[1].fQuadratics + fTallies[1].fQuadratics; - - // Cubics (loops and serpentines) view the same instance buffer as an array of CubicInstance[]. - // So, reinterpreting the instance data as CubicInstance[], we start them on the first index - // that will not overwrite previous TriangleInstance data. + // We already know how big to make each of the 6 arrays from fTotalPrimitiveCounts, so layout is + // straightforward. Start with triangles and quadratics. They both view the instance buffer as + // an array of TriangleInstance[], so we can begin at zero and lay them out one after the other. + fBaseInstances[0].fTriangles = 0; + fBaseInstances[1].fTriangles = fBaseInstances[0].fTriangles + + fTotalPrimitiveCounts[0].fTriangles; + fBaseInstances[0].fQuadratics = fBaseInstances[1].fTriangles + + fTotalPrimitiveCounts[1].fTriangles; + fBaseInstances[1].fQuadratics = fBaseInstances[0].fQuadratics + + fTotalPrimitiveCounts[0].fQuadratics; + int triEndIdx = fBaseInstances[1].fQuadratics + fTotalPrimitiveCounts[1].fQuadratics; + + // Cubics view the same instance buffer as an array of CubicInstance[]. So, reinterpreting the + // instance data as CubicInstance[], we start them on the first index that will not overwrite + // previous TriangleInstance data. int cubicBaseIdx = GR_CT_DIV_ROUND_UP(triEndIdx * sizeof(TriangleInstance), sizeof(CubicInstance)); - baseInstances[0].fCubics = cubicBaseIdx; - baseInstances[1].fCubics = baseInstances[0].fCubics + fTallies[0].fCubics; - int cubicEndIdx = baseInstances[1].fCubics + fTallies[1].fCubics; + fBaseInstances[0].fCubics = cubicBaseIdx; + fBaseInstances[1].fCubics = fBaseInstances[0].fCubics + fTotalPrimitiveCounts[0].fCubics; + int cubicEndIdx = fBaseInstances[1].fCubics + fTotalPrimitiveCounts[1].fCubics; - sk_sp<GrBuffer> instanceBuffer = - onFlushRP->makeBuffer(kVertex_GrBufferType, cubicEndIdx * sizeof(CubicInstance)); - if (!instanceBuffer) { + fInstanceBuffer = onFlushRP->makeBuffer(kVertex_GrBufferType, + cubicEndIdx * sizeof(CubicInstance)); + if (!fInstanceBuffer) { return false; } - TriangleInstance* triangleInstanceData = static_cast<TriangleInstance*>(instanceBuffer->map()); + TriangleInstance* triangleInstanceData = static_cast<TriangleInstance*>(fInstanceBuffer->map()); CubicInstance* cubicInstanceData = reinterpret_cast<CubicInstance*>(triangleInstanceData); SkASSERT(cubicInstanceData); @@ -265,16 +283,10 @@ bool GrCCCoverageOpsBuilder::finalize(GrOnFlushResourceProvider* onFlushRP, float atlasOffsetX = 0.0, atlasOffsetY = 0.0; Sk2f atlasOffset; int ptsIdx = -1; - PrimitiveTallies instanceIndices[2] = {baseInstances[0], baseInstances[1]}; + PrimitiveTallies instanceIndices[2] = {fBaseInstances[0], fBaseInstances[1]}; PrimitiveTallies* currIndices = nullptr; SkSTArray<256, int32_t, true> currFan; -#ifdef SK_DEBUG - int numScissoredPaths = 0; - int numScissorBatches = 0; - PrimitiveTallies initialBaseInstances[] = {baseInstances[0], baseInstances[1]}; -#endif - const SkTArray<SkPoint, true>& pts = fGeometry.points(); // Expand the ccpr verbs into GPU instance buffers. @@ -286,18 +298,6 @@ bool GrCCCoverageOpsBuilder::finalize(GrOnFlushResourceProvider* onFlushRP, atlasOffsetX = static_cast<float>(currPathInfo->fAtlasOffsetX); atlasOffsetY = static_cast<float>(currPathInfo->fAtlasOffsetY); atlasOffset = {atlasOffsetX, atlasOffsetY}; -#ifdef SK_DEBUG - if (ScissorMode::kScissored == currPathInfo->fScissorMode) { - ++numScissoredPaths; - } -#endif - if (auto op = std::move(currPathInfo->fTerminatingOp)) { - op->setInstanceBuffer(instanceBuffer, baseInstances, instanceIndices); - baseInstances[0] = instanceIndices[0]; - baseInstances[1] = instanceIndices[1]; - SkDEBUGCODE(numScissorBatches += op->fScissorBatches.count()); - ops->push_back(std::move(op)); - } ++currPathInfo; continue; @@ -345,37 +345,25 @@ bool GrCCCoverageOpsBuilder::finalize(GrOnFlushResourceProvider* onFlushRP, } } - instanceBuffer->unmap(); - - if (auto op = std::move(fTerminatingOp)) { - op->setInstanceBuffer(std::move(instanceBuffer), baseInstances, instanceIndices); - SkDEBUGCODE(numScissorBatches += op->fScissorBatches.count()); - ops->push_back(std::move(op)); - } + fInstanceBuffer->unmap(); SkASSERT(currPathInfo == fPathsInfo.end()); SkASSERT(ptsIdx == pts.count() - 1); - SkASSERT(numScissoredPaths == numScissorBatches); - SkASSERT(instanceIndices[0].fTriangles == initialBaseInstances[1].fTriangles); - SkASSERT(instanceIndices[1].fTriangles == initialBaseInstances[0].fQuadratics); - SkASSERT(instanceIndices[0].fQuadratics == initialBaseInstances[1].fQuadratics); + SkASSERT(instanceIndices[0].fTriangles == fBaseInstances[1].fTriangles); + SkASSERT(instanceIndices[1].fTriangles == fBaseInstances[0].fQuadratics); + SkASSERT(instanceIndices[0].fQuadratics == fBaseInstances[1].fQuadratics); SkASSERT(instanceIndices[1].fQuadratics == triEndIdx); - SkASSERT(instanceIndices[0].fCubics == initialBaseInstances[1].fCubics); + SkASSERT(instanceIndices[0].fCubics == fBaseInstances[1].fCubics); SkASSERT(instanceIndices[1].fCubics == cubicEndIdx); - return true; -} -void GrCCCoverageOp::setInstanceBuffer(sk_sp<GrBuffer> instanceBuffer, - const PrimitiveTallies baseInstances[kNumScissorModes], - const PrimitiveTallies endInstances[kNumScissorModes]) { - fInstanceBuffer = std::move(instanceBuffer); - fBaseInstances[0] = baseInstances[0]; - fBaseInstances[1] = baseInstances[1]; - fInstanceCounts[0] = endInstances[0] - baseInstances[0]; - fInstanceCounts[1] = endInstances[1] - baseInstances[1]; + fMeshesScratchBuffer.reserve(fMaxMeshesPerDraw); + fDynamicStatesScratchBuffer.reserve(fMaxMeshesPerDraw); + + return true; } -void GrCCCoverageOp::onExecute(GrOpFlushState* flushState) { +void GrCCPathParser::drawCoverageCount(GrOpFlushState* flushState, CoverageCountBatchID batchID, + const SkIRect& drawBounds) const { using RenderPass = GrCCCoverageProcessor::RenderPass; SkASSERT(fInstanceBuffer); @@ -383,76 +371,84 @@ void GrCCCoverageOp::onExecute(GrOpFlushState* flushState) { GrPipeline pipeline(flushState->drawOpArgs().fProxy, GrPipeline::ScissorState::kEnabled, SkBlendMode::kPlus); - fMeshesScratchBuffer.reserve(1 + fScissorBatches.count()); - fDynamicStatesScratchBuffer.reserve(1 + fScissorBatches.count()); - // Triangles. - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleHulls, - &PrimitiveTallies::fTriangles); - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleEdges, - &PrimitiveTallies::fTriangles); // Might get skipped. - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kTriangleCorners, - &PrimitiveTallies::fTriangles); + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleHulls, + &PrimitiveTallies::fTriangles, drawBounds); + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleEdges, + &PrimitiveTallies::fTriangles, drawBounds); // Might get skipped. + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kTriangleCorners, + &PrimitiveTallies::fTriangles, drawBounds); // Quadratics. - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kQuadraticHulls, - &PrimitiveTallies::fQuadratics); - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kQuadraticCorners, - &PrimitiveTallies::fQuadratics); + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kQuadraticHulls, + &PrimitiveTallies::fQuadratics, drawBounds); + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kQuadraticCorners, + &PrimitiveTallies::fQuadratics, drawBounds); // Cubics. - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kCubicHulls, - &PrimitiveTallies::fCubics); - this->drawMaskPrimitives(flushState, pipeline, RenderPass::kCubicCorners, - &PrimitiveTallies::fCubics); + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kCubicHulls, + &PrimitiveTallies::fCubics, drawBounds); + this->drawRenderPass(flushState, pipeline, batchID, RenderPass::kCubicCorners, + &PrimitiveTallies::fCubics, drawBounds); } -void GrCCCoverageOp::drawMaskPrimitives(GrOpFlushState* flushState, const GrPipeline& pipeline, - GrCCCoverageProcessor::RenderPass renderPass, - int PrimitiveTallies::*instanceType) const { - using ScissorMode = GrCCCoverageOpsBuilder::ScissorMode; +void GrCCPathParser::drawRenderPass(GrOpFlushState* flushState, const GrPipeline& pipeline, + CoverageCountBatchID batchID, + GrCCCoverageProcessor::RenderPass renderPass, + int PrimitiveTallies::*instanceType, + const SkIRect& drawBounds) const { SkASSERT(pipeline.getScissorState().enabled()); if (!GrCCCoverageProcessor::DoesRenderPass(renderPass, *flushState->caps().shaderCaps())) { return; } - fMeshesScratchBuffer.reset(); - fDynamicStatesScratchBuffer.reset(); + // Don't call reset(), as that also resets the reserve count. + fMeshesScratchBuffer.pop_back_n(fMeshesScratchBuffer.count()); + fDynamicStatesScratchBuffer.pop_back_n(fDynamicStatesScratchBuffer.count()); GrCCCoverageProcessor proc(flushState->resourceProvider(), renderPass, *flushState->caps().shaderCaps()); - if (int instanceCount = fInstanceCounts[(int)ScissorMode::kNonScissored].*instanceType) { + SkASSERT(batchID > 0); + SkASSERT(batchID < fCoverageCountBatches.count()); + const CoverageCountBatch& previousBatch = fCoverageCountBatches[batchID - 1]; + const CoverageCountBatch& batch = fCoverageCountBatches[batchID]; + + if (int instanceCount = batch.fEndNonScissorIndices.*instanceType - + previousBatch.fEndNonScissorIndices.*instanceType) { SkASSERT(instanceCount > 0); - int baseInstance = fBaseInstances[(int)ScissorMode::kNonScissored].*instanceType; + int baseInstance = fBaseInstances[(int)ScissorMode::kNonScissored].*instanceType + + previousBatch.fEndNonScissorIndices.*instanceType; proc.appendMesh(fInstanceBuffer.get(), instanceCount, baseInstance, &fMeshesScratchBuffer); - fDynamicStatesScratchBuffer.push_back().fScissorRect.setXYWH(0, 0, fDrawBounds.width(), - fDrawBounds.height()); + fDynamicStatesScratchBuffer.push_back().fScissorRect.setXYWH(0, 0, drawBounds.width(), + drawBounds.height()); } - if (fInstanceCounts[(int)ScissorMode::kScissored].*instanceType) { - int baseInstance = fBaseInstances[(int)ScissorMode::kScissored].*instanceType; - for (const ScissorBatch& batch : fScissorBatches) { - SkASSERT(this->bounds().contains(batch.fScissor)); - const int instanceCount = batch.fInstanceCounts.*instanceType; - if (!instanceCount) { - continue; - } - SkASSERT(instanceCount > 0); - proc.appendMesh(fInstanceBuffer.get(), instanceCount, baseInstance, - &fMeshesScratchBuffer); - fDynamicStatesScratchBuffer.push_back().fScissorRect = batch.fScissor; - baseInstance += instanceCount; + SkASSERT(previousBatch.fEndScissorSubBatchIdx > 0); + SkASSERT(batch.fEndScissorSubBatchIdx <= fScissorSubBatches.count()); + int baseScissorInstance = fBaseInstances[(int)ScissorMode::kScissored].*instanceType; + for (int i = previousBatch.fEndScissorSubBatchIdx; i < batch.fEndScissorSubBatchIdx; ++i) { + const ScissorSubBatch& previousSubBatch = fScissorSubBatches[i - 1]; + const ScissorSubBatch& scissorSubBatch = fScissorSubBatches[i]; + int startIndex = previousSubBatch.fEndPrimitiveIndices.*instanceType; + int instanceCount = scissorSubBatch.fEndPrimitiveIndices.*instanceType - startIndex; + if (!instanceCount) { + continue; } + SkASSERT(instanceCount > 0); + proc.appendMesh(fInstanceBuffer.get(), instanceCount, + baseScissorInstance + startIndex, &fMeshesScratchBuffer); + fDynamicStatesScratchBuffer.push_back().fScissorRect = scissorSubBatch.fScissor; } SkASSERT(fMeshesScratchBuffer.count() == fDynamicStatesScratchBuffer.count()); + SkASSERT(fMeshesScratchBuffer.count() <= fMaxMeshesPerDraw); if (!fMeshesScratchBuffer.empty()) { SkASSERT(flushState->rtCommandBuffer()); flushState->rtCommandBuffer()->draw(pipeline, proc, fMeshesScratchBuffer.begin(), fDynamicStatesScratchBuffer.begin(), - fMeshesScratchBuffer.count(), this->bounds()); + fMeshesScratchBuffer.count(), SkRect::Make(drawBounds)); } } diff --git a/src/gpu/ccpr/GrCCPathParser.h b/src/gpu/ccpr/GrCCPathParser.h new file mode 100644 index 0000000000..aff6b1069d --- /dev/null +++ b/src/gpu/ccpr/GrCCPathParser.h @@ -0,0 +1,124 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrCCPathParser_DEFINED +#define GrCCPathParser_DEFINED + +#include "GrMesh.h" +#include "GrNonAtomicRef.h" +#include "SkRect.h" +#include "SkRefCnt.h" +#include "ccpr/GrCCCoverageProcessor.h" +#include "ccpr/GrCCGeometry.h" +#include "ops/GrDrawOp.h" + +class GrOnFlushResourceProvider; +class SkMatrix; +class SkPath; + +/** + * This class parses SkPaths into CCPR primitives in GPU buffers, then issues calls to draw their + * coverage counts. + */ +class GrCCPathParser : public GrNonAtomicRef<GrCCPathParser> { +public: + // Indicates whether a path should enforce a scissor clip when rendering its mask. (Specified + // as an int because these values get used directly as indices into arrays.) + enum class ScissorMode : int { kNonScissored = 0, kScissored = 1 }; + static constexpr int kNumScissorModes = 2; + + GrCCPathParser(int maxTotalPaths, int maxPathPoints, int numSkPoints, int numSkVerbs); + + ~GrCCPathParser() { + // Enforce the contract that the client always calls saveParsedPath or discardParsedPath. + SkASSERT(!fParsingPath); + } + + using CoverageCountBatchID = int; + + // Parses an SkPath into a temporary staging area. The path will not be included in the current + // batch until there is a matching call to saveParsedPath. The user must complement this with a + // following call to either saveParsedPath or discardParsedPath. + // + // Returns two tight bounding boxes: device space and "45 degree" (| 1 -1 | * devCoords) space. + // | 1 1 | + void parsePath(const SkMatrix&, const SkPath&, SkRect* devBounds, SkRect* devBounds45); + + // Parses a device-space SkPath into a temporary staging area. The path will not be included in + // the current batch until there is a matching call to saveParsedPath. The user must complement + // this with a following call to either saveParsedPath or discardParsedPath. + void parseDeviceSpacePath(const SkPath&); + + // Commits the currently-parsed path from staging to the current batch, and specifies whether + // the mask should be rendered with a scissor in effect. Accepts an optional post-device-space + // translate for placement in an atlas. + void saveParsedPath(ScissorMode, const SkIRect& clippedDevIBounds, int16_t atlasOffsetX, + int16_t atlasOffsetY); + void discardParsedPath(); + + // Compiles the outstanding saved paths into a batch, and returns an ID that can be used to draw + // their coverage counts in the future. + CoverageCountBatchID closeCurrentBatch(); + + // Builds internal GPU buffers and prepares for calls to drawCoverageCount. Caller must close + // the current batch before calling this method, and cannot parse new paths afer. + bool finalize(GrOnFlushResourceProvider*); + + // Called after finalize. Draws the given batch of parsed paths. + void drawCoverageCount(GrOpFlushState*, CoverageCountBatchID, const SkIRect& drawBounds) const; + +private: + using PrimitiveTallies = GrCCGeometry::PrimitiveTallies; + + // Every kBeginPath verb has a corresponding PathInfo entry. + struct PathInfo { + ScissorMode fScissorMode; + int16_t fAtlasOffsetX, fAtlasOffsetY; + }; + + // Defines a batch of CCPR primitives. Start indices are deduced by looking at the previous + // CoverageCountBatch in the list. + struct CoverageCountBatch { + PrimitiveTallies fEndNonScissorIndices; + int fEndScissorSubBatchIdx; + }; + + // Defines a sub-batch from CoverageCountBatch that will be drawn with the given scissor rect. + // Start indices are deduced by looking at the previous ScissorSubBatch in the list. + struct ScissorSubBatch { + PrimitiveTallies fEndPrimitiveIndices; + SkIRect fScissor; + }; + + void parsePath(const SkPath&, const SkPoint* deviceSpacePts); + void endContourIfNeeded(bool insideContour); + + void drawRenderPass(GrOpFlushState*, const GrPipeline&, CoverageCountBatchID, + GrCCCoverageProcessor::RenderPass, int PrimitiveTallies::*instanceType, + const SkIRect& drawBounds) const; + + // Staging area for the path being parsed. + SkDEBUGCODE(int fParsingPath = false); + const SkAutoSTArray<32, SkPoint> fLocalDevPtsBuffer; + int fCurrPathPointsIdx; + int fCurrPathVerbsIdx; + PrimitiveTallies fCurrPathPrimitiveCounts; + + GrCCGeometry fGeometry; + SkSTArray<32, PathInfo, true> fPathsInfo; + SkSTArray<32, CoverageCountBatch, true> fCoverageCountBatches; + SkSTArray<32, ScissorSubBatch, true> fScissorSubBatches; + PrimitiveTallies fTotalPrimitiveCounts[kNumScissorModes]; + int fMaxMeshesPerDraw = 0; + + sk_sp<GrBuffer> fInstanceBuffer; + PrimitiveTallies fBaseInstances[kNumScissorModes]; + mutable SkSTArray<32, GrMesh> fMeshesScratchBuffer; + mutable SkSTArray<32, GrPipeline::DynamicState> fDynamicStatesScratchBuffer; +}; + +#endif diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index 91074cb714..d78f28abd0 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -277,6 +277,7 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush SkASSERT(!fPerFlushIndexBuffer); SkASSERT(!fPerFlushVertexBuffer); SkASSERT(!fPerFlushInstanceBuffer); + SkASSERT(!fPerFlushPathParser); SkASSERT(fPerFlushAtlases.empty()); SkDEBUGCODE(fFlushing = true); @@ -347,7 +348,8 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush SkASSERT(pathInstanceData); int pathInstanceIdx = 0; - GrCCCoverageOpsBuilder atlasOpsBuilder(maxTotalPaths, maxPathPoints, numSkPoints, numSkVerbs); + fPerFlushPathParser = sk_make_sp<GrCCPathParser>(maxTotalPaths, maxPathPoints, numSkPoints, + numSkVerbs); SkDEBUGCODE(int skippedTotalPaths = 0); // Allocate atlas(es) and fill out GPU instance buffers. @@ -362,14 +364,13 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush drawOpsIter.init(rtPendingPaths.fDrawOps, SkTInternalLList<DrawPathsOp>::Iter::kHead_IterStart); while (DrawPathsOp* op = drawOpsIter.get()) { - pathInstanceIdx = op->setupResources(onFlushRP, &atlasOpsBuilder, pathInstanceData, - pathInstanceIdx); + pathInstanceIdx = op->setupResources(onFlushRP, pathInstanceData, pathInstanceIdx); drawOpsIter.next(); SkDEBUGCODE(skippedTotalPaths += op->numSkippedInstances_debugOnly()); } for (auto& clipsIter : rtPendingPaths.fClipPaths) { - clipsIter.second.placePathInAtlas(this, onFlushRP, &atlasOpsBuilder); + clipsIter.second.placePathInAtlas(this, onFlushRP, fPerFlushPathParser.get()); } } @@ -378,36 +379,30 @@ void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlush SkASSERT(pathInstanceIdx == maxTotalPaths - skippedTotalPaths - numClipPaths); if (!fPerFlushAtlases.empty()) { - atlasOpsBuilder.emitOp(fPerFlushAtlases.back().drawBounds()); + auto coverageCountBatchID = fPerFlushPathParser->closeCurrentBatch(); + fPerFlushAtlases.back().setCoverageCountBatchID(coverageCountBatchID); } - SkSTArray<4, std::unique_ptr<GrCCCoverageOp>> atlasOps(fPerFlushAtlases.count()); - if (!atlasOpsBuilder.finalize(onFlushRP, &atlasOps)) { - SkDebugf("WARNING: failed to allocate ccpr atlas buffers. No paths will be drawn.\n"); + if (!fPerFlushPathParser->finalize(onFlushRP)) { + SkDebugf("WARNING: failed to allocate GPU buffers for CCPR. No paths will be drawn.\n"); return; } - SkASSERT(atlasOps.count() == fPerFlushAtlases.count()); - // Draw the coverage ops into their respective atlases. + // Draw the atlas(es). GrTAllocator<GrCCAtlas>::Iter atlasIter(&fPerFlushAtlases); - for (std::unique_ptr<GrCCCoverageOp>& atlasOp : atlasOps) { - SkAssertResult(atlasIter.next()); - GrCCAtlas* atlas = atlasIter.get(); - SkASSERT(atlasOp->bounds() == - SkRect::MakeIWH(atlas->drawBounds().width(), atlas->drawBounds().height())); - if (auto rtc = atlas->finalize(onFlushRP, std::move(atlasOp))) { + while (atlasIter.next()) { + if (auto rtc = atlasIter.get()->finalize(onFlushRP, fPerFlushPathParser)) { results->push_back(std::move(rtc)); } } - SkASSERT(!atlasIter.next()); fPerFlushResourcesAreValid = true; } int CCPR::DrawPathsOp::setupResources(GrOnFlushResourceProvider* onFlushRP, - GrCCCoverageOpsBuilder* atlasOpsBuilder, GrCCPathProcessor::Instance* pathInstanceData, int pathInstanceIdx) { + GrCCPathParser* parser = fCCPR->fPerFlushPathParser.get(); const GrCCAtlas* currentAtlas = nullptr; SkASSERT(fInstanceCount > 0); SkASSERT(-1 == fBaseInstance); @@ -418,14 +413,14 @@ int CCPR::DrawPathsOp::setupResources(GrOnFlushResourceProvider* onFlushRP, // one rotated an additional 45 degrees. The path vertex shader uses these two bounding // boxes to generate an octagon that circumscribes the path. SkRect devBounds, devBounds45; - atlasOpsBuilder->parsePath(draw->fMatrix, draw->fPath, &devBounds, &devBounds45); + parser->parsePath(draw->fMatrix, draw->fPath, &devBounds, &devBounds45); SkIRect devIBounds; devBounds.roundOut(&devIBounds); int16_t offsetX, offsetY; GrCCAtlas* atlas = fCCPR->placeParsedPathInAtlas(onFlushRP, draw->fClipIBounds, devIBounds, - &offsetX, &offsetY, atlasOpsBuilder); + &offsetX, &offsetY); if (!atlas) { SkDEBUGCODE(++fNumSkippedInstances); continue; @@ -457,12 +452,12 @@ int CCPR::DrawPathsOp::setupResources(GrOnFlushResourceProvider* onFlushRP, void CCPR::ClipPath::placePathInAtlas(GrCoverageCountingPathRenderer* ccpr, GrOnFlushResourceProvider* onFlushRP, - GrCCCoverageOpsBuilder* atlasOpsBuilder) { + GrCCPathParser* parser) { SkASSERT(!this->isUninitialized()); SkASSERT(!fHasAtlas); - atlasOpsBuilder->parseDeviceSpacePath(fDeviceSpacePath); + parser->parseDeviceSpacePath(fDeviceSpacePath); fAtlas = ccpr->placeParsedPathInAtlas(onFlushRP, fAccessRect, fPathDevIBounds, &fAtlasOffsetX, - &fAtlasOffsetY, atlasOpsBuilder); + &fAtlasOffsetY); SkDEBUGCODE(fHasAtlas = true); } @@ -471,9 +466,8 @@ GrCCAtlas* GrCoverageCountingPathRenderer::placeParsedPathInAtlas( const SkIRect& clipIBounds, const SkIRect& pathIBounds, int16_t* atlasOffsetX, - int16_t* atlasOffsetY, - GrCCCoverageOpsBuilder* atlasOpsBuilder) { - using ScissorMode = GrCCCoverageOpsBuilder::ScissorMode; + int16_t* atlasOffsetY) { + using ScissorMode = GrCCPathParser::ScissorMode; ScissorMode scissorMode; SkIRect clippedPathIBounds; @@ -483,23 +477,25 @@ GrCCAtlas* GrCoverageCountingPathRenderer::placeParsedPathInAtlas( } else if (clippedPathIBounds.intersect(clipIBounds, pathIBounds)) { scissorMode = ScissorMode::kScissored; } else { - atlasOpsBuilder->discardParsedPath(); + fPerFlushPathParser->discardParsedPath(); return nullptr; } SkIPoint16 atlasLocation; - const int h = clippedPathIBounds.height(), w = clippedPathIBounds.width(); + int h = clippedPathIBounds.height(), w = clippedPathIBounds.width(); if (fPerFlushAtlases.empty() || !fPerFlushAtlases.back().addRect(w, h, &atlasLocation)) { if (!fPerFlushAtlases.empty()) { // The atlas is out of room and can't grow any bigger. - atlasOpsBuilder->emitOp(fPerFlushAtlases.back().drawBounds()); + auto coverageCountBatchID = fPerFlushPathParser->closeCurrentBatch(); + fPerFlushAtlases.back().setCoverageCountBatchID(coverageCountBatchID); } fPerFlushAtlases.emplace_back(*onFlushRP->caps(), w, h).addRect(w, h, &atlasLocation); } *atlasOffsetX = atlasLocation.x() - static_cast<int16_t>(clippedPathIBounds.left()); *atlasOffsetY = atlasLocation.y() - static_cast<int16_t>(clippedPathIBounds.top()); - atlasOpsBuilder->saveParsedPath(scissorMode, clippedPathIBounds, *atlasOffsetX, *atlasOffsetY); + fPerFlushPathParser->saveParsedPath(scissorMode, clippedPathIBounds, *atlasOffsetX, + *atlasOffsetY); return &fPerFlushAtlases.back(); } @@ -553,6 +549,7 @@ void GrCoverageCountingPathRenderer::postFlush(GrDeferredUploadToken, const uint int numOpListIDs) { SkASSERT(fFlushing); fPerFlushAtlases.reset(); + fPerFlushPathParser.reset(); fPerFlushInstanceBuffer.reset(); fPerFlushVertexBuffer.reset(); fPerFlushIndexBuffer.reset(); diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h index 4fb3cc7a6b..40b9d5d06e 100644 --- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.h +++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.h @@ -14,7 +14,7 @@ #include "GrPathRenderer.h" #include "SkTInternalLList.h" #include "ccpr/GrCCAtlas.h" -#include "ccpr/GrCCCoverageOp.h" +#include "ccpr/GrCCPathParser.h" #include "ccpr/GrCCPathProcessor.h" #include "ops/GrDrawOp.h" @@ -77,7 +77,7 @@ public: void onPrepare(GrOpFlushState*) override {} void onExecute(GrOpFlushState*) override; - int setupResources(GrOnFlushResourceProvider*, GrCCCoverageOpsBuilder*, + int setupResources(GrOnFlushResourceProvider*, GrCCPathProcessor::Instance* pathInstanceData, int pathInstanceIdx); private: @@ -156,7 +156,7 @@ public: return fPathDevIBounds; } void placePathInAtlas(GrCoverageCountingPathRenderer*, GrOnFlushResourceProvider*, - GrCCCoverageOpsBuilder*); + GrCCPathParser*); const SkVector& atlasScale() const { SkASSERT(fHasAtlasTransform); @@ -201,7 +201,7 @@ private: GrCCAtlas* placeParsedPathInAtlas(GrOnFlushResourceProvider*, const SkIRect& accessRect, const SkIRect& pathIBounds, int16_t* atlasOffsetX, - int16_t* atlasOffsetY, GrCCCoverageOpsBuilder*); + int16_t* atlasOffsetY); struct RTPendingPaths { ~RTPendingPaths() { @@ -221,6 +221,7 @@ private: sk_sp<const GrBuffer> fPerFlushIndexBuffer; sk_sp<const GrBuffer> fPerFlushVertexBuffer; sk_sp<GrBuffer> fPerFlushInstanceBuffer; + sk_sp<GrCCPathParser> fPerFlushPathParser; GrSTAllocator<4, GrCCAtlas> fPerFlushAtlases; bool fPerFlushResourcesAreValid; SkDEBUGCODE(bool fFlushing = false); |