1 /*
2 * Copyright 2015 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 #include "GrDrawPathOp.h"
9 #include "GrAppliedClip.h"
10 #include "GrRenderTargetContext.h"
11 #include "GrRenderTargetPriv.h"
12 #include "SkTemplates.h"
13
GrDrawPathOpBase(uint32_t classID,const SkMatrix & viewMatrix,GrPaint && paint,GrPathRendering::FillType fill,GrAAType aaType)14 GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
15 GrPathRendering::FillType fill, GrAAType aaType)
16 : INHERITED(classID)
17 , fViewMatrix(viewMatrix)
18 , fInputColor(paint.getColor())
19 , fFillType(fill)
20 , fAAType(aaType)
21 , fPipelineSRGBFlags(GrPipeline::SRGBFlagsFromPaint(paint))
22 , fProcessorSet(std::move(paint)) {}
23
dumpInfo() const24 SkString GrDrawPathOp::dumpInfo() const {
25 SkString string;
26 string.printf("PATH: 0x%p", fPath.get());
27 string.append(INHERITED::dumpInfo());
28 return string;
29 }
30
pipelineInitArgs(const GrOpFlushState & state)31 GrPipeline::InitArgs GrDrawPathOpBase::pipelineInitArgs(const GrOpFlushState& state) {
32 static constexpr GrUserStencilSettings kCoverPass{
33 GrUserStencilSettings::StaticInit<
34 0x0000,
35 GrUserStencilTest::kNotEqual,
36 0xffff,
37 GrUserStencilOp::kZero,
38 GrUserStencilOp::kKeep,
39 0xffff>()
40 };
41 GrPipeline::InitArgs args;
42 args.fFlags = fPipelineSRGBFlags;
43 if (GrAATypeIsHW(fAAType)) {
44 args.fFlags |= GrPipeline::kHWAntialias_Flag;
45 }
46 args.fUserStencil = &kCoverPass;
47 args.fProxy = state.drawOpArgs().fProxy;
48 args.fCaps = &state.caps();
49 args.fResourceProvider = state.resourceProvider();
50 args.fDstProxy = state.drawOpArgs().fDstProxy;
51 return args;
52 }
53
54 //////////////////////////////////////////////////////////////////////////////
55
init_stencil_pass_settings(const GrOpFlushState & flushState,GrPathRendering::FillType fillType,GrStencilSettings * stencil)56 void init_stencil_pass_settings(const GrOpFlushState& flushState,
57 GrPathRendering::FillType fillType, GrStencilSettings* stencil) {
58 const GrAppliedClip* appliedClip = flushState.drawOpArgs().fAppliedClip;
59 bool stencilClip = appliedClip && appliedClip->hasStencilClip();
60 stencil->reset(GrPathRendering::GetStencilPassSettings(fillType), stencilClip,
61 flushState.drawOpArgs().renderTarget()->renderTargetPriv().numStencilBits());
62 }
63
64 //////////////////////////////////////////////////////////////////////////////
65
onExecute(GrOpFlushState * state)66 void GrDrawPathOp::onExecute(GrOpFlushState* state) {
67 GrPipeline pipeline(this->pipelineInitArgs(*state), this->detachProcessors(),
68 state->detachAppliedClip());
69 sk_sp<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(), this->viewMatrix()));
70
71 GrStencilSettings stencil;
72 init_stencil_pass_settings(*state, this->fillType(), &stencil);
73 state->gpu()->pathRendering()->drawPath(pipeline, *pathProc, stencil, fPath.get());
74 }
75
76 //////////////////////////////////////////////////////////////////////////////
77
dumpInfo() const78 SkString GrDrawPathRangeOp::dumpInfo() const {
79 SkString string;
80 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
81 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
82 string.appendf("%d, ", iter.get()->fInstanceData->count());
83 }
84 string.remove(string.size() - 2, 2);
85 string.append("]");
86 string.append(INHERITED::dumpInfo());
87 return string;
88 }
89
GrDrawPathRangeOp(const SkMatrix & viewMatrix,SkScalar scale,SkScalar x,SkScalar y,GrPaint && paint,GrPathRendering::FillType fill,GrAAType aaType,GrPathRange * range,const InstanceData * instanceData,const SkRect & bounds)90 GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
91 SkScalar y, GrPaint&& paint, GrPathRendering::FillType fill,
92 GrAAType aaType, GrPathRange* range,
93 const InstanceData* instanceData, const SkRect& bounds)
94 : INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aaType)
95 , fPathRange(range)
96 , fTotalPathCount(instanceData->count())
97 , fScale(scale) {
98 fDraws.addToHead()->set(instanceData, x, y);
99 this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
100 }
101
102 static void pre_translate_transform_values(const float* xforms,
103 GrPathRendering::PathTransformType type, int count,
104 SkScalar x, SkScalar y, float* dst);
105
onCombineIfPossible(GrOp * t,const GrCaps & caps)106 bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
107 GrDrawPathRangeOp* that = t->cast<GrDrawPathRangeOp>();
108 if (this->fPathRange.get() != that->fPathRange.get() ||
109 this->transformType() != that->transformType() || this->fScale != that->fScale ||
110 this->color() != that->color() || !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
111 return false;
112 }
113 if (this->processors() != that->processors()) {
114 return false;
115 }
116 if (this->pipelineSRGBFlags() != that->pipelineSRGBFlags()) {
117 return false;
118 }
119 switch (fDraws.head()->fInstanceData->transformType()) {
120 case GrPathRendering::kNone_PathTransformType:
121 if (this->fDraws.head()->fX != that->fDraws.head()->fX ||
122 this->fDraws.head()->fY != that->fDraws.head()->fY) {
123 return false;
124 }
125 break;
126 case GrPathRendering::kTranslateX_PathTransformType:
127 if (this->fDraws.head()->fY != that->fDraws.head()->fY) {
128 return false;
129 }
130 break;
131 case GrPathRendering::kTranslateY_PathTransformType:
132 if (this->fDraws.head()->fX != that->fDraws.head()->fX) {
133 return false;
134 }
135 break;
136 default:
137 break;
138 }
139 // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...)
140 // Try to combine this call with the previous DrawPaths. We do this by stenciling all the
141 // paths together and then covering them in a single pass. This is not equivalent to two
142 // separate draw calls, so we can only do it if there is no blending (no overlap would also
143 // work). Note that it's also possible for overlapping paths to cancel each other's winding
144 // numbers, and we only partially account for this by not allowing even/odd paths to be
145 // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.)
146
147 if (GrPathRendering::kWinding_FillType != this->fillType() ||
148 GrPathRendering::kWinding_FillType != that->fillType()) {
149 return false;
150 }
151 if (!this->processorAnalysis().canCombineOverlappedStencilAndCover()) {
152 return false;
153 }
154 fTotalPathCount += that->fTotalPathCount;
155 while (Draw* head = that->fDraws.head()) {
156 Draw* draw = fDraws.addToTail();
157 draw->fInstanceData.reset(head->fInstanceData.release());
158 draw->fX = head->fX;
159 draw->fY = head->fY;
160 that->fDraws.popHead();
161 }
162 this->joinBounds(*that);
163 return true;
164 }
165
onExecute(GrOpFlushState * state)166 void GrDrawPathRangeOp::onExecute(GrOpFlushState* state) {
167 const Draw& head = *fDraws.head();
168
169 SkMatrix drawMatrix(this->viewMatrix());
170 drawMatrix.preScale(fScale, fScale);
171 drawMatrix.preTranslate(head.fX, head.fY);
172
173 SkMatrix localMatrix;
174 localMatrix.setScale(fScale, fScale);
175 localMatrix.preTranslate(head.fX, head.fY);
176
177 sk_sp<GrPathProcessor> pathProc(
178 GrPathProcessor::Create(this->color(), drawMatrix, localMatrix));
179
180 GrPipeline pipeline(this->pipelineInitArgs(*state), this->detachProcessors(),
181 state->detachAppliedClip());
182 GrStencilSettings stencil;
183 init_stencil_pass_settings(*state, this->fillType(), &stencil);
184 if (fDraws.count() == 1) {
185 const InstanceData& instances = *head.fInstanceData;
186 state->gpu()->pathRendering()->drawPaths(pipeline,
187 *pathProc,
188 stencil,
189 fPathRange.get(),
190 instances.indices(),
191 GrPathRange::kU16_PathIndexType,
192 instances.transformValues(),
193 instances.transformType(),
194 instances.count());
195 } else {
196 int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType());
197 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
198 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
199 int idx = 0;
200 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
201 const Draw& draw = *iter.get();
202 const InstanceData& instances = *draw.fInstanceData;
203 memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t));
204 pre_translate_transform_values(instances.transformValues(), this->transformType(),
205 instances.count(), draw.fX - head.fX, draw.fY - head.fY,
206 &transformStorage[floatsPerTransform * idx]);
207 idx += instances.count();
208
209 // TODO: Support mismatched transform types if we start using more types other than 2D.
210 SkASSERT(instances.transformType() == this->transformType());
211 }
212 SkASSERT(idx == fTotalPathCount);
213
214 state->gpu()->pathRendering()->drawPaths(pipeline,
215 *pathProc,
216 stencil,
217 fPathRange.get(),
218 indexStorage,
219 GrPathRange::kU16_PathIndexType,
220 transformStorage,
221 this->transformType(),
222 fTotalPathCount);
223 }
224 }
225
pre_translate_transform_values(const float * xforms,GrPathRendering::PathTransformType type,int count,SkScalar x,SkScalar y,float * dst)226 inline void pre_translate_transform_values(const float* xforms,
227 GrPathRendering::PathTransformType type, int count,
228 SkScalar x, SkScalar y, float* dst) {
229 if (0 == x && 0 == y) {
230 memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
231 return;
232 }
233 switch (type) {
234 case GrPathRendering::kNone_PathTransformType:
235 SK_ABORT("Cannot pre-translate kNone_PathTransformType.");
236 break;
237 case GrPathRendering::kTranslateX_PathTransformType:
238 SkASSERT(0 == y);
239 for (int i = 0; i < count; i++) {
240 dst[i] = xforms[i] + x;
241 }
242 break;
243 case GrPathRendering::kTranslateY_PathTransformType:
244 SkASSERT(0 == x);
245 for (int i = 0; i < count; i++) {
246 dst[i] = xforms[i] + y;
247 }
248 break;
249 case GrPathRendering::kTranslate_PathTransformType:
250 for (int i = 0; i < 2 * count; i += 2) {
251 dst[i] = xforms[i] + x;
252 dst[i + 1] = xforms[i + 1] + y;
253 }
254 break;
255 case GrPathRendering::kAffine_PathTransformType:
256 for (int i = 0; i < 6 * count; i += 6) {
257 dst[i] = xforms[i];
258 dst[i + 1] = xforms[i + 1];
259 dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
260 dst[i + 3] = xforms[i + 3];
261 dst[i + 4] = xforms[i + 4];
262 dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
263 }
264 break;
265 default:
266 SK_ABORT("Unknown transform type.");
267 break;
268 }
269 }
270