| /* |
| * Copyright 2018 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #ifndef GrCCStroker_DEFINED |
| #define GrCCStroker_DEFINED |
| |
| #include "GrAllocator.h" |
| #include "GrMesh.h" |
| #include "SkNx.h" |
| #include "ccpr/GrCCStrokeGeometry.h" |
| |
| class GrBuffer; |
| class GrCCCoverageProcessor; |
| class GrOnFlushResourceProvider; |
| class GrOpFlushState; |
| class GrPipeline; |
| class GrPrimitiveProcessor; |
| class SkMatrix; |
| class SkPath; |
| class SkStrokeRec; |
| |
| /** |
| * This class parses stroked SkPaths into a GPU instance buffer, then issues calls to draw their |
| * coverage counts. |
| */ |
| class GrCCStroker { |
| public: |
| GrCCStroker(int numPaths, int numSkPoints, int numSkVerbs) |
| : fGeometry(numSkPoints, numSkVerbs), fPathInfos(numPaths) {} |
| |
| // Parses a device-space SkPath into the current batch, using the SkPath's original verbs with |
| // 'deviceSpacePts', and the SkStrokeRec's original settings with 'strokeDevWidth'. Accepts an |
| // optional post-device-space translate for placement in an atlas. |
| // |
| // Strokes intended as hairlines must have a strokeDevWidth of 1. Non-hairline strokes can only |
| // be drawn with rigid body transforms; affine transformation of the stroke lines themselves is |
| // not yet supported. |
| void parseDeviceSpaceStroke(const SkPath&, const SkPoint* deviceSpacePts, const SkStrokeRec&, |
| float strokeDevWidth, GrScissorTest, |
| const SkIRect& clippedDevIBounds, |
| const SkIVector& devToAtlasOffset); |
| |
| using BatchID = int; |
| |
| // Compiles the outstanding parsed paths into a batch, and returns an ID that can be used to |
| // draw their strokes in the future. |
| BatchID closeCurrentBatch(); |
| |
| // Builds an internal GPU buffer and prepares for calls to drawStrokes(). Caller must close the |
| // current batch before calling this method, and cannot parse new paths afer. |
| bool prepareToDraw(GrOnFlushResourceProvider*); |
| |
| // Called after prepareToDraw(). Draws the given batch of path strokes. |
| void drawStrokes(GrOpFlushState*, BatchID, const SkIRect& drawBounds) const; |
| |
| private: |
| static constexpr int kNumScissorModes = 2; |
| static constexpr BatchID kEmptyBatchID = -1; |
| using Verb = GrCCStrokeGeometry::Verb; |
| using InstanceTallies = GrCCStrokeGeometry::InstanceTallies; |
| |
| // Every kBeginPath verb has a corresponding PathInfo entry. |
| struct PathInfo { |
| SkIVector fDevToAtlasOffset; |
| float fStrokeRadius; |
| GrScissorTest fScissorTest; |
| }; |
| |
| // Defines a sub-batch of stroke instances that have a scissor test and the same scissor rect. |
| // Start indices are deduced by looking at the previous ScissorSubBatch. |
| struct ScissorSubBatch { |
| ScissorSubBatch(GrTAllocator<InstanceTallies>* alloc, const InstanceTallies& startIndices, |
| const SkIRect& scissor) |
| : fEndInstances(&alloc->emplace_back(startIndices)), fScissor(scissor) {} |
| InstanceTallies* fEndInstances; |
| SkIRect fScissor; |
| }; |
| |
| // Defines a batch of stroke instances that can be drawn with drawStrokes(). Start indices are |
| // deduced by looking at the previous Batch in the list. |
| struct Batch { |
| Batch(GrTAllocator<InstanceTallies>* alloc, const InstanceTallies& startNonScissorIndices, |
| int startScissorSubBatch) |
| : fNonScissorEndInstances(&alloc->emplace_back(startNonScissorIndices)) |
| , fEndScissorSubBatch(startScissorSubBatch) {} |
| InstanceTallies* fNonScissorEndInstances; |
| int fEndScissorSubBatch; |
| }; |
| |
| class InstanceBufferBuilder; |
| |
| void appendStrokeMeshesToBuffers(int numSegmentsLog2, const Batch&, |
| const InstanceTallies* startIndices[2], |
| int startScissorSubBatch, const SkIRect& drawBounds) const; |
| void flushBufferedMeshesAsStrokes(const GrPrimitiveProcessor&, GrOpFlushState*, const |
| GrPipeline&, const SkIRect& drawBounds) const; |
| |
| template<int GrCCStrokeGeometry::InstanceTallies::* InstanceType> |
| void drawConnectingGeometry(GrOpFlushState*, const GrPipeline&, |
| const GrCCCoverageProcessor&, const Batch&, |
| const InstanceTallies* startIndices[2], int startScissorSubBatch, |
| const SkIRect& drawBounds) const; |
| |
| GrCCStrokeGeometry fGeometry; |
| SkSTArray<32, PathInfo> fPathInfos; |
| SkSTArray<32, Batch> fBatches; |
| SkSTArray<32, ScissorSubBatch> fScissorSubBatches; |
| int fMaxNumScissorSubBatches = 0; |
| bool fHasOpenBatch = false; |
| |
| const InstanceTallies fZeroTallies = InstanceTallies(); |
| GrSTAllocator<128, InstanceTallies> fTalliesAllocator; |
| const InstanceTallies* fInstanceCounts[kNumScissorModes] = {&fZeroTallies, &fZeroTallies}; |
| |
| sk_sp<GrBuffer> fInstanceBuffer; |
| // The indices stored in batches are relative to these base instances. |
| InstanceTallies fBaseInstances[kNumScissorModes]; |
| |
| mutable SkSTArray<32, GrMesh> fMeshesBuffer; |
| mutable SkSTArray<32, SkIRect> fScissorsBuffer; |
| }; |
| |
| #endif |