1/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrCCStroker_DEFINED
9#define GrCCStroker_DEFINED
10
11#include "include/private/GrTypesPriv.h"
12#include "include/private/SkNx.h"
13#include "src/gpu/GrTAllocator.h"
14#include "src/gpu/ccpr/GrCCStrokeGeometry.h"
15
16class GrGpuBuffer;
17class GrCCCoverageProcessor;
18class GrOnFlushResourceProvider;
19class GrOpFlushState;
20class GrPipeline;
21class GrPrimitiveProcessor;
22class SkMatrix;
23class SkPath;
24class SkStrokeRec;
25
26/**
27 * This class parses stroked SkPaths into a GPU instance buffer, then issues calls to draw their
28 * coverage counts.
29 */
30class GrCCStroker {
31public:
32 GrCCStroker(int numPaths, int numSkPoints, int numSkVerbs)
33 : fGeometry(numSkPoints, numSkVerbs), fPathInfos(numPaths) {}
34
35 // Parses a device-space SkPath into the current batch, using the SkPath's original verbs with
36 // 'deviceSpacePts', and the SkStrokeRec's original settings with 'strokeDevWidth'. Accepts an
37 // optional post-device-space translate for placement in an atlas.
38 //
39 // Strokes intended as hairlines must have a strokeDevWidth of 1. Non-hairline strokes can only
40 // be drawn with rigid body transforms; affine transformation of the stroke lines themselves is
41 // not yet supported.
42 void parseDeviceSpaceStroke(const SkPath&, const SkPoint* deviceSpacePts, const SkStrokeRec&,
43 float strokeDevWidth, GrScissorTest,
44 const SkIRect& clippedDevIBounds,
45 const SkIVector& devToAtlasOffset);
46
47 using BatchID = int;
48
49 // Compiles the outstanding parsed paths into a batch, and returns an ID that can be used to
50 // draw their strokes in the future.
51 BatchID closeCurrentBatch();
52
53 // Builds an internal GPU buffer and prepares for calls to drawStrokes(). Caller must close the
54 // current batch before calling this method, and cannot parse new paths afer.
55 bool prepareToDraw(GrOnFlushResourceProvider*);
56
57 // Called after prepareToDraw(). Draws the given batch of path strokes.
58 void drawStrokes(
59 GrOpFlushState*, GrCCCoverageProcessor*, BatchID, const SkIRect& drawBounds) const;
60
61private:
62 static constexpr int kNumScissorModes = 2;
63 static constexpr BatchID kEmptyBatchID = -1;
64 using Verb = GrCCStrokeGeometry::Verb;
65 using InstanceTallies = GrCCStrokeGeometry::InstanceTallies;
66 using InstanceTalliesAllocator = GrTAllocator<InstanceTallies, 128>;
67
68 // Every kBeginPath verb has a corresponding PathInfo entry.
69 struct PathInfo {
70 SkIVector fDevToAtlasOffset;
71 float fStrokeRadius;
72 GrScissorTest fScissorTest;
73 };
74
75 // Defines a sub-batch of stroke instances that have a scissor test and the same scissor rect.
76 // Start indices are deduced by looking at the previous ScissorSubBatch.
77 struct ScissorSubBatch {
78 ScissorSubBatch(InstanceTalliesAllocator* alloc, const InstanceTallies& startIndices,
79 const SkIRect& scissor)
80 : fEndInstances(&alloc->emplace_back(startIndices)), fScissor(scissor) {}
81 InstanceTallies* fEndInstances;
82 SkIRect fScissor;
83 };
84
85 // Defines a batch of stroke instances that can be drawn with drawStrokes(). Start indices are
86 // deduced by looking at the previous Batch in the list.
87 struct Batch {
88 Batch(InstanceTalliesAllocator* alloc, const InstanceTallies& startNonScissorIndices,
89 int startScissorSubBatch)
90 : fNonScissorEndInstances(&alloc->emplace_back(startNonScissorIndices))
91 , fEndScissorSubBatch(startScissorSubBatch) {}
92 InstanceTallies* fNonScissorEndInstances;
93 int fEndScissorSubBatch;
94 };
95
96 class InstanceBufferBuilder;
97
98 // Draws a batch of strokes by chopping them into "2^numSegmentsLog2" linear segments each.
99 void drawLog2Strokes(int numSegmentsLog2, GrOpFlushState*, const GrPrimitiveProcessor&,
100 const GrPipeline&, const Batch&, const InstanceTallies* startIndices[2],
101 int startScissorSubBatch, const SkIRect& drawBounds) const;
102
103 template<int GrCCStrokeGeometry::InstanceTallies::* InstanceType>
104 void drawConnectingGeometry(GrOpFlushState*, const GrPipeline&,
105 const GrCCCoverageProcessor&, const Batch&,
106 const InstanceTallies* startIndices[2], int startScissorSubBatch,
107 const SkIRect& drawBounds) const;
108
109 GrCCStrokeGeometry fGeometry;
110 SkSTArray<32, PathInfo> fPathInfos;
111 SkSTArray<32, Batch> fBatches;
112 SkSTArray<32, ScissorSubBatch> fScissorSubBatches;
113 int fMaxNumScissorSubBatches = 0;
114 bool fHasOpenBatch = false;
115
116 const InstanceTallies fZeroTallies = InstanceTallies();
117 InstanceTalliesAllocator fTalliesAllocator;
118 const InstanceTallies* fInstanceCounts[kNumScissorModes] = {&fZeroTallies, &fZeroTallies};
119
120 sk_sp<GrGpuBuffer> fInstanceBuffer;
121 // The indices stored in batches are relative to these base instances.
122 InstanceTallies fBaseInstances[kNumScissorModes];
123};
124
125#endif
126