blob: 0a3df45cae56321152f815fa0802d699e14b64b5 [file] [log] [blame]
bsalomon1fcc01c2015-09-09 09:48:06 -07001/*
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
Brian Salomon82c263f2016-12-15 09:54:06 -05008#include "GrDrawPathOp.h"
Brian Salomon54d212e2017-03-21 14:22:38 -04009#include "GrAppliedClip.h"
10#include "GrRenderTargetContext.h"
Brian Salomonc48af932017-03-16 19:51:42 +000011#include "GrRenderTargetPriv.h"
Brian Salomon54d212e2017-03-21 14:22:38 -040012#include "SkTemplates.h"
Brian Salomonc48af932017-03-16 19:51:42 +000013
Brian Salomon54d212e2017-03-21 14:22:38 -040014GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
15 GrPathRendering::FillType fill, GrAA aa)
16 : INHERITED(classID)
17 , fViewMatrix(viewMatrix)
18 , fProcessorSet(std::move(paint))
19 , fAnalysis(paint.getColor())
20 , fFillType(fill)
21 , fAA(aa) {}
cdalton193d9cf2016-05-12 11:52:02 -070022
Brian Salomon82c263f2016-12-15 09:54:06 -050023SkString GrDrawPathOp::dumpInfo() const {
bsalomon1fcc01c2015-09-09 09:48:06 -070024 SkString string;
stephana1dc17212016-04-25 07:01:22 -070025 string.printf("PATH: 0x%p", fPath.get());
robertphillips44fbc792016-06-29 06:56:12 -070026 string.append(INHERITED::dumpInfo());
bsalomon1fcc01c2015-09-09 09:48:06 -070027 return string;
28}
29
Brian Salomon54d212e2017-03-21 14:22:38 -040030GrPipelineOptimizations GrDrawPathOpBase::initPipeline(const GrOpFlushState& state,
31 GrPipeline* pipeline) {
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.fProcessors = &this->processors();
43 args.fFlags = GrAA::kYes == fAA ? GrPipeline::kHWAntialias_Flag : 0;
44 args.fUserStencil = &kCoverPass;
45 args.fAppliedClip = state.drawOpArgs().fAppliedClip;
46 args.fRenderTarget = state.drawOpArgs().fRenderTarget;
47 args.fCaps = &state.caps();
48 args.fDstTexture = state.drawOpArgs().fDstTexture;
49 args.fAnalysis =
50 &this->doFragmentProcessorAnalysis(state.caps(), state.drawOpArgs().fAppliedClip);
Brian Salomon2bf4b3a2017-03-16 14:19:07 -040051
Brian Salomon54d212e2017-03-21 14:22:38 -040052 return pipeline->init(args);
Brian Salomon2bf4b3a2017-03-16 14:19:07 -040053}
54
Brian Salomon54d212e2017-03-21 14:22:38 -040055//////////////////////////////////////////////////////////////////////////////
56
57void init_stencil_pass_settings(const GrOpFlushState& flushState,
58 GrPathRendering::FillType fillType, GrStencilSettings* stencil) {
59 const GrAppliedClip* appliedClip = flushState.drawOpArgs().fAppliedClip;
60 bool stencilClip = appliedClip && appliedClip->hasStencilClip();
61 stencil->reset(GrPathRendering::GetStencilPassSettings(fillType), stencilClip,
62 flushState.drawOpArgs().fRenderTarget->renderTargetPriv().numStencilBits());
63}
64
65//////////////////////////////////////////////////////////////////////////////
66
67void GrDrawPathOp::onExecute(GrOpFlushState* state) {
68 GrColor color = this->color();
69 GrPipeline pipeline;
70 GrPipelineOptimizations optimizations = this->initPipeline(*state, &pipeline);
71 optimizations.getOverrideColorIfSet(&color);
72 sk_sp<GrPathProcessor> pathProc(GrPathProcessor::Create(color, this->viewMatrix()));
73
74 GrStencilSettings stencil;
75 init_stencil_pass_settings(*state, this->fillType(), &stencil);
76 state->gpu()->pathRendering()->drawPath(pipeline, *pathProc, stencil, fPath.get());
77}
78
79//////////////////////////////////////////////////////////////////////////////
80
Brian Salomon82c263f2016-12-15 09:54:06 -050081SkString GrDrawPathRangeOp::dumpInfo() const {
bsalomon1fcc01c2015-09-09 09:48:06 -070082 SkString string;
cdaltoncdd46822015-12-08 10:48:31 -080083 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
bsalomon1fcc01c2015-09-09 09:48:06 -070084 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
cdaltoncdd46822015-12-08 10:48:31 -080085 string.appendf("%d, ", iter.get()->fInstanceData->count());
bsalomon1fcc01c2015-09-09 09:48:06 -070086 }
87 string.remove(string.size() - 2, 2);
88 string.append("]");
robertphillips44fbc792016-06-29 06:56:12 -070089 string.append(INHERITED::dumpInfo());
bsalomon1fcc01c2015-09-09 09:48:06 -070090 return string;
91}
92
Brian Salomon82c263f2016-12-15 09:54:06 -050093GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
Brian Salomon54d212e2017-03-21 14:22:38 -040094 SkScalar y, GrPaint&& paint, GrPathRendering::FillType fill,
95 GrAA aa, GrPathRange* range, const InstanceData* instanceData,
Brian Salomon82c263f2016-12-15 09:54:06 -050096 const SkRect& bounds)
Brian Salomon54d212e2017-03-21 14:22:38 -040097 : INHERITED(ClassID(), viewMatrix, std::move(paint), fill, aa)
Brian Salomon82c263f2016-12-15 09:54:06 -050098 , fPathRange(range)
99 , fTotalPathCount(instanceData->count())
100 , fScale(scale) {
cdaltoncdd46822015-12-08 10:48:31 -0800101 fDraws.addToHead()->set(instanceData, x, y);
bsalomon88cf17d2016-07-08 06:40:56 -0700102 this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
bsalomon1fcc01c2015-09-09 09:48:06 -0700103}
104
Brian Salomon54d212e2017-03-21 14:22:38 -0400105static void pre_translate_transform_values(const float* xforms,
106 GrPathRendering::PathTransformType type, int count,
107 SkScalar x, SkScalar y, float* dst);
108
Brian Salomon82c263f2016-12-15 09:54:06 -0500109bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
110 GrDrawPathRangeOp* that = t->cast<GrDrawPathRangeOp>();
cdaltoncdd46822015-12-08 10:48:31 -0800111 if (this->fPathRange.get() != that->fPathRange.get() ||
Brian Salomon82c263f2016-12-15 09:54:06 -0500112 this->transformType() != that->transformType() || this->fScale != that->fScale ||
113 this->color() != that->color() || !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
bsalomon1fcc01c2015-09-09 09:48:06 -0700114 return false;
115 }
Brian Salomon54d212e2017-03-21 14:22:38 -0400116 if (this->processors() != that->processors()) {
bsalomon1fcc01c2015-09-09 09:48:06 -0700117 return false;
118 }
cdaltoncdd46822015-12-08 10:48:31 -0800119 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;
Brian Salomon82c263f2016-12-15 09:54:06 -0500136 default:
137 break;
bsalomon1fcc01c2015-09-09 09:48:06 -0700138 }
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.)
Brian Salomon54d212e2017-03-21 14:22:38 -0400146
cdalton8ff8d242015-12-08 10:20:32 -0800147 if (GrPathRendering::kWinding_FillType != this->fillType() ||
Brian Salomon54d212e2017-03-21 14:22:38 -0400148 GrPathRendering::kWinding_FillType != that->fillType()) {
bsalomon1fcc01c2015-09-09 09:48:06 -0700149 return false;
150 }
Brian Salomon31853842017-03-28 16:32:05 -0400151 if (!this->fragmentProcessorAnalysis().canCombineOverlappedStencilAndCover()) {
Brian Salomon54d212e2017-03-21 14:22:38 -0400152 return false;
153 }
bsalomon1fcc01c2015-09-09 09:48:06 -0700154 fTotalPathCount += that->fTotalPathCount;
cdaltoncdd46822015-12-08 10:48:31 -0800155 while (Draw* head = that->fDraws.head()) {
156 Draw* draw = fDraws.addToTail();
mtklein18300a32016-03-16 13:53:35 -0700157 draw->fInstanceData.reset(head->fInstanceData.release());
cdaltoncdd46822015-12-08 10:48:31 -0800158 draw->fX = head->fX;
159 draw->fY = head->fY;
bsalomon1fcc01c2015-09-09 09:48:06 -0700160 that->fDraws.popHead();
161 }
bsalomon88cf17d2016-07-08 06:40:56 -0700162 this->joinBounds(*that);
bsalomon1fcc01c2015-09-09 09:48:06 -0700163 return true;
164}
165
Brian Salomon9e50f7b2017-03-06 12:02:34 -0500166void GrDrawPathRangeOp::onExecute(GrOpFlushState* state) {
cdaltoncdd46822015-12-08 10:48:31 -0800167 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
Brian Salomon82c263f2016-12-15 09:54:06 -0500177 sk_sp<GrPathProcessor> pathProc(
Brian Salomonecea86a2017-01-04 13:25:17 -0500178 GrPathProcessor::Create(this->color(), drawMatrix, localMatrix));
cdaltoncdd46822015-12-08 10:48:31 -0800179
Brian Salomon54d212e2017-03-21 14:22:38 -0400180 GrPipeline pipeline;
181 this->initPipeline(*state, &pipeline);
182 GrStencilSettings stencil;
183 init_stencil_pass_settings(*state, this->fillType(), &stencil);
bsalomon1fcc01c2015-09-09 09:48:06 -0700184 if (fDraws.count() == 1) {
cdaltoncdd46822015-12-08 10:48:31 -0800185 const InstanceData& instances = *head.fInstanceData;
Brian Salomon54d212e2017-03-21 14:22:38 -0400186 state->gpu()->pathRendering()->drawPaths(pipeline,
egdaniel0e1853c2016-03-17 11:35:45 -0700187 *pathProc,
Brian Salomon54d212e2017-03-21 14:22:38 -0400188 stencil,
egdaniel0e1853c2016-03-17 11:35:45 -0700189 fPathRange.get(),
190 instances.indices(),
cdaltoncdd46822015-12-08 10:48:31 -0800191 GrPathRange::kU16_PathIndexType,
192 instances.transformValues(),
193 instances.transformType(),
194 instances.count());
195 } else {
196 int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType());
cdaltoncdd46822015-12-08 10:48:31 -0800197 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
198 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
cdaltoncdd46822015-12-08 10:48:31 -0800199 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(),
Brian Salomon82c263f2016-12-15 09:54:06 -0500205 instances.count(), draw.fX - head.fX, draw.fY - head.fY,
cdaltoncdd46822015-12-08 10:48:31 -0800206 &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
Brian Salomon54d212e2017-03-21 14:22:38 -0400214 state->gpu()->pathRendering()->drawPaths(pipeline,
egdaniel0e1853c2016-03-17 11:35:45 -0700215 *pathProc,
Brian Salomon54d212e2017-03-21 14:22:38 -0400216 stencil,
egdaniel0e1853c2016-03-17 11:35:45 -0700217 fPathRange.get(),
218 indexStorage,
219 GrPathRange::kU16_PathIndexType,
220 transformStorage,
221 this->transformType(),
222 fTotalPathCount);
cdaltoncdd46822015-12-08 10:48:31 -0800223 }
224}
225
226inline 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));
bsalomon1fcc01c2015-09-09 09:48:06 -0700231 return;
232 }
cdaltoncdd46822015-12-08 10:48:31 -0800233 switch (type) {
234 case GrPathRendering::kNone_PathTransformType:
235 SkFAIL("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 SkFAIL("Unknown transform type.");
267 break;
bsalomon1fcc01c2015-09-09 09:48:06 -0700268 }
bsalomon1fcc01c2015-09-09 09:48:06 -0700269}