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