blob: a32d7080e0507929962b0701b3435a63007d4bb3 [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"
bsalomon1fcc01c2015-09-09 09:48:06 -07009
cdalton193d9cf2016-05-12 11:52:02 -070010#include "GrRenderTargetPriv.h"
11
cdaltoncdd46822015-12-08 10:48:31 -080012static void pre_translate_transform_values(const float* xforms,
13 GrPathRendering::PathTransformType type, int count,
14 SkScalar x, SkScalar y, float* dst);
15
Brian Salomon82c263f2016-12-15 09:54:06 -050016void GrDrawPathOpBase::onPrepare(GrOpFlushState*) {
cdalton193d9cf2016-05-12 11:52:02 -070017 const GrRenderTargetPriv& rtPriv = this->pipeline()->getRenderTarget()->renderTargetPriv();
18 fStencilPassSettings.reset(GrPathRendering::GetStencilPassSettings(fFillType),
19 this->pipeline()->hasStencilClip(), rtPriv.numStencilBits());
20}
21
Brian Salomon82c263f2016-12-15 09:54:06 -050022SkString GrDrawPathOp::dumpInfo() const {
bsalomon1fcc01c2015-09-09 09:48:06 -070023 SkString string;
stephana1dc17212016-04-25 07:01:22 -070024 string.printf("PATH: 0x%p", fPath.get());
Brian Salomon7c3e7182016-12-01 09:35:30 -050025 string.append(DumpPipelineInfo(*this->pipeline()));
robertphillips44fbc792016-06-29 06:56:12 -070026 string.append(INHERITED::dumpInfo());
bsalomon1fcc01c2015-09-09 09:48:06 -070027 return string;
28}
29
Brian Salomonbde42852016-12-21 11:37:49 -050030void GrDrawPathOp::onExecute(GrOpFlushState* state, const SkRect& bounds) {
Brian Salomon82c263f2016-12-15 09:54:06 -050031 GrProgramDesc desc;
stephana1dc17212016-04-25 07:01:22 -070032
Brian Salomon82c263f2016-12-15 09:54:06 -050033 sk_sp<GrPathProcessor> pathProc(
Brian Salomonecea86a2017-01-04 13:25:17 -050034 GrPathProcessor::Create(this->color(), this->viewMatrix()));
cdalton193d9cf2016-05-12 11:52:02 -070035 state->gpu()->pathRendering()->drawPath(*this->pipeline(), *pathProc,
36 this->stencilPassSettings(), fPath.get());
bsalomon1fcc01c2015-09-09 09:48:06 -070037}
38
Brian Salomon82c263f2016-12-15 09:54:06 -050039SkString GrDrawPathRangeOp::dumpInfo() const {
bsalomon1fcc01c2015-09-09 09:48:06 -070040 SkString string;
cdaltoncdd46822015-12-08 10:48:31 -080041 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
bsalomon1fcc01c2015-09-09 09:48:06 -070042 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
cdaltoncdd46822015-12-08 10:48:31 -080043 string.appendf("%d, ", iter.get()->fInstanceData->count());
bsalomon1fcc01c2015-09-09 09:48:06 -070044 }
45 string.remove(string.size() - 2, 2);
46 string.append("]");
Brian Salomon7c3e7182016-12-01 09:35:30 -050047 string.append(DumpPipelineInfo(*this->pipeline()));
robertphillips44fbc792016-06-29 06:56:12 -070048 string.append(INHERITED::dumpInfo());
bsalomon1fcc01c2015-09-09 09:48:06 -070049 return string;
50}
51
Brian Salomon82c263f2016-12-15 09:54:06 -050052GrDrawPathRangeOp::GrDrawPathRangeOp(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
53 SkScalar y, GrColor color, GrPathRendering::FillType fill,
54 GrPathRange* range, const InstanceData* instanceData,
55 const SkRect& bounds)
56 : INHERITED(ClassID(), viewMatrix, color, fill)
57 , fPathRange(range)
58 , fTotalPathCount(instanceData->count())
59 , fScale(scale) {
cdaltoncdd46822015-12-08 10:48:31 -080060 fDraws.addToHead()->set(instanceData, x, y);
bsalomon88cf17d2016-07-08 06:40:56 -070061 this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
bsalomon1fcc01c2015-09-09 09:48:06 -070062}
63
Brian Salomon82c263f2016-12-15 09:54:06 -050064bool GrDrawPathRangeOp::onCombineIfPossible(GrOp* t, const GrCaps& caps) {
65 GrDrawPathRangeOp* that = t->cast<GrDrawPathRangeOp>();
cdaltoncdd46822015-12-08 10:48:31 -080066 if (this->fPathRange.get() != that->fPathRange.get() ||
Brian Salomon82c263f2016-12-15 09:54:06 -050067 this->transformType() != that->transformType() || this->fScale != that->fScale ||
68 this->color() != that->color() || !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
bsalomon1fcc01c2015-09-09 09:48:06 -070069 return false;
70 }
bsalomon7312ff82016-09-12 08:55:38 -070071 if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline())) {
bsalomon1fcc01c2015-09-09 09:48:06 -070072 return false;
73 }
cdaltoncdd46822015-12-08 10:48:31 -080074 switch (fDraws.head()->fInstanceData->transformType()) {
75 case GrPathRendering::kNone_PathTransformType:
76 if (this->fDraws.head()->fX != that->fDraws.head()->fX ||
77 this->fDraws.head()->fY != that->fDraws.head()->fY) {
78 return false;
79 }
80 break;
81 case GrPathRendering::kTranslateX_PathTransformType:
82 if (this->fDraws.head()->fY != that->fDraws.head()->fY) {
83 return false;
84 }
85 break;
86 case GrPathRendering::kTranslateY_PathTransformType:
87 if (this->fDraws.head()->fX != that->fDraws.head()->fX) {
88 return false;
89 }
90 break;
Brian Salomon82c263f2016-12-15 09:54:06 -050091 default:
92 break;
bsalomon1fcc01c2015-09-09 09:48:06 -070093 }
94 // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...)
95 // Try to combine this call with the previous DrawPaths. We do this by stenciling all the
96 // paths together and then covering them in a single pass. This is not equivalent to two
97 // separate draw calls, so we can only do it if there is no blending (no overlap would also
98 // work). Note that it's also possible for overlapping paths to cancel each other's winding
99 // numbers, and we only partially account for this by not allowing even/odd paths to be
100 // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.)
cdalton8ff8d242015-12-08 10:20:32 -0800101 if (GrPathRendering::kWinding_FillType != this->fillType() ||
cdalton193d9cf2016-05-12 11:52:02 -0700102 GrPathRendering::kWinding_FillType != that->fillType() ||
Brian Salomonecea86a2017-01-04 13:25:17 -0500103 this->blendsWithDst()) {
bsalomon1fcc01c2015-09-09 09:48:06 -0700104 return false;
105 }
Brian Salomonecea86a2017-01-04 13:25:17 -0500106 SkASSERT(!that->blendsWithDst());
bsalomon1fcc01c2015-09-09 09:48:06 -0700107 fTotalPathCount += that->fTotalPathCount;
cdaltoncdd46822015-12-08 10:48:31 -0800108 while (Draw* head = that->fDraws.head()) {
109 Draw* draw = fDraws.addToTail();
mtklein18300a32016-03-16 13:53:35 -0700110 draw->fInstanceData.reset(head->fInstanceData.release());
cdaltoncdd46822015-12-08 10:48:31 -0800111 draw->fX = head->fX;
112 draw->fY = head->fY;
bsalomon1fcc01c2015-09-09 09:48:06 -0700113 that->fDraws.popHead();
114 }
bsalomon88cf17d2016-07-08 06:40:56 -0700115 this->joinBounds(*that);
bsalomon1fcc01c2015-09-09 09:48:06 -0700116 return true;
117}
118
Brian Salomonbde42852016-12-21 11:37:49 -0500119void GrDrawPathRangeOp::onExecute(GrOpFlushState* state, const SkRect& bounds) {
cdaltoncdd46822015-12-08 10:48:31 -0800120 const Draw& head = *fDraws.head();
121
122 SkMatrix drawMatrix(this->viewMatrix());
123 drawMatrix.preScale(fScale, fScale);
124 drawMatrix.preTranslate(head.fX, head.fY);
125
126 SkMatrix localMatrix;
127 localMatrix.setScale(fScale, fScale);
128 localMatrix.preTranslate(head.fX, head.fY);
129
Brian Salomon82c263f2016-12-15 09:54:06 -0500130 sk_sp<GrPathProcessor> pathProc(
Brian Salomonecea86a2017-01-04 13:25:17 -0500131 GrPathProcessor::Create(this->color(), drawMatrix, localMatrix));
cdaltoncdd46822015-12-08 10:48:31 -0800132
bsalomon1fcc01c2015-09-09 09:48:06 -0700133 if (fDraws.count() == 1) {
cdaltoncdd46822015-12-08 10:48:31 -0800134 const InstanceData& instances = *head.fInstanceData;
egdaniel0e1853c2016-03-17 11:35:45 -0700135 state->gpu()->pathRendering()->drawPaths(*this->pipeline(),
136 *pathProc,
cdalton193d9cf2016-05-12 11:52:02 -0700137 this->stencilPassSettings(),
egdaniel0e1853c2016-03-17 11:35:45 -0700138 fPathRange.get(),
139 instances.indices(),
cdaltoncdd46822015-12-08 10:48:31 -0800140 GrPathRange::kU16_PathIndexType,
141 instances.transformValues(),
142 instances.transformType(),
143 instances.count());
144 } else {
145 int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType());
cdaltoncdd46822015-12-08 10:48:31 -0800146 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
147 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
cdaltoncdd46822015-12-08 10:48:31 -0800148 int idx = 0;
149 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
150 const Draw& draw = *iter.get();
151 const InstanceData& instances = *draw.fInstanceData;
152 memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t));
153 pre_translate_transform_values(instances.transformValues(), this->transformType(),
Brian Salomon82c263f2016-12-15 09:54:06 -0500154 instances.count(), draw.fX - head.fX, draw.fY - head.fY,
cdaltoncdd46822015-12-08 10:48:31 -0800155 &transformStorage[floatsPerTransform * idx]);
156 idx += instances.count();
157
158 // TODO: Support mismatched transform types if we start using more types other than 2D.
159 SkASSERT(instances.transformType() == this->transformType());
160 }
161 SkASSERT(idx == fTotalPathCount);
162
egdaniel0e1853c2016-03-17 11:35:45 -0700163 state->gpu()->pathRendering()->drawPaths(*this->pipeline(),
164 *pathProc,
cdalton193d9cf2016-05-12 11:52:02 -0700165 this->stencilPassSettings(),
egdaniel0e1853c2016-03-17 11:35:45 -0700166 fPathRange.get(),
167 indexStorage,
168 GrPathRange::kU16_PathIndexType,
169 transformStorage,
170 this->transformType(),
171 fTotalPathCount);
cdaltoncdd46822015-12-08 10:48:31 -0800172 }
173}
174
175inline void pre_translate_transform_values(const float* xforms,
176 GrPathRendering::PathTransformType type, int count,
177 SkScalar x, SkScalar y, float* dst) {
178 if (0 == x && 0 == y) {
179 memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
bsalomon1fcc01c2015-09-09 09:48:06 -0700180 return;
181 }
cdaltoncdd46822015-12-08 10:48:31 -0800182 switch (type) {
183 case GrPathRendering::kNone_PathTransformType:
184 SkFAIL("Cannot pre-translate kNone_PathTransformType.");
185 break;
186 case GrPathRendering::kTranslateX_PathTransformType:
187 SkASSERT(0 == y);
188 for (int i = 0; i < count; i++) {
189 dst[i] = xforms[i] + x;
190 }
191 break;
192 case GrPathRendering::kTranslateY_PathTransformType:
193 SkASSERT(0 == x);
194 for (int i = 0; i < count; i++) {
195 dst[i] = xforms[i] + y;
196 }
197 break;
198 case GrPathRendering::kTranslate_PathTransformType:
199 for (int i = 0; i < 2 * count; i += 2) {
200 dst[i] = xforms[i] + x;
201 dst[i + 1] = xforms[i + 1] + y;
202 }
203 break;
204 case GrPathRendering::kAffine_PathTransformType:
205 for (int i = 0; i < 6 * count; i += 6) {
206 dst[i] = xforms[i];
207 dst[i + 1] = xforms[i + 1];
208 dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
209 dst[i + 3] = xforms[i + 3];
210 dst[i + 4] = xforms[i + 4];
211 dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
212 }
213 break;
214 default:
215 SkFAIL("Unknown transform type.");
216 break;
bsalomon1fcc01c2015-09-09 09:48:06 -0700217 }
bsalomon1fcc01c2015-09-09 09:48:06 -0700218}