blob: ff62539932261568f20e19a3140b9655e1d817d0 [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
8#include "GrDrawPathBatch.h"
9
cdaltoncdd46822015-12-08 10:48:31 -080010static void pre_translate_transform_values(const float* xforms,
11 GrPathRendering::PathTransformType type, int count,
12 SkScalar x, SkScalar y, float* dst);
13
bsalomon1fcc01c2015-09-09 09:48:06 -070014SkString GrDrawPathBatch::dumpInfo() const {
15 SkString string;
16 string.printf("PATH: 0x%p", fPath.get());
17 return string;
18}
19
20void GrDrawPathBatch::onDraw(GrBatchFlushState* state) {
21 GrProgramDesc desc;
joshualittf2384692015-09-10 11:00:51 -070022
23 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
ethannicholasff210322015-11-24 12:10:10 -080024 this->overrides(),
joshualittf2384692015-09-10 11:00:51 -070025 this->viewMatrix()));
joshualitt465283c2015-09-11 08:19:35 -070026 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline());
joshualittf2384692015-09-10 11:00:51 -070027 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(),
joshualitt465283c2015-09-11 08:19:35 -070028 &desc, &this->stencilSettings());
bsalomon1fcc01c2015-09-09 09:48:06 -070029 state->gpu()->pathRendering()->drawPath(args, fPath.get());
30}
31
bsalomon1fcc01c2015-09-09 09:48:06 -070032SkString GrDrawPathRangeBatch::dumpInfo() const {
33 SkString string;
cdaltoncdd46822015-12-08 10:48:31 -080034 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
bsalomon1fcc01c2015-09-09 09:48:06 -070035 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
cdaltoncdd46822015-12-08 10:48:31 -080036 string.appendf("%d, ", iter.get()->fInstanceData->count());
bsalomon1fcc01c2015-09-09 09:48:06 -070037 }
38 string.remove(string.size() - 2, 2);
39 string.append("]");
40 return string;
41}
42
cdaltoncdd46822015-12-08 10:48:31 -080043GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
44 SkScalar y, GrColor color,
45 GrPathRendering::FillType fill, GrPathRange* range,
46 const InstanceData* instanceData, const SkRect& bounds)
cdalton8ff8d242015-12-08 10:20:32 -080047 : INHERITED(ClassID(), viewMatrix, color, fill)
cdalton8585dd22015-10-08 08:04:09 -070048 , fPathRange(range)
cdaltoncdd46822015-12-08 10:48:31 -080049 , fTotalPathCount(instanceData->count())
50 , fScale(scale) {
51 fDraws.addToHead()->set(instanceData, x, y);
bsalomonbf074552015-11-23 14:25:19 -080052 fBounds = bounds;
bsalomon1fcc01c2015-09-09 09:48:06 -070053}
54
55bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
56 GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>();
cdaltoncdd46822015-12-08 10:48:31 -080057 if (this->fPathRange.get() != that->fPathRange.get() ||
58 this->transformType() != that->transformType() ||
59 this->fScale != that->fScale ||
60 this->color() != that->color() ||
61 !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
bsalomon1fcc01c2015-09-09 09:48:06 -070062 return false;
63 }
64 if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline(), false)) {
65 return false;
66 }
cdaltoncdd46822015-12-08 10:48:31 -080067 switch (fDraws.head()->fInstanceData->transformType()) {
68 case GrPathRendering::kNone_PathTransformType:
69 if (this->fDraws.head()->fX != that->fDraws.head()->fX ||
70 this->fDraws.head()->fY != that->fDraws.head()->fY) {
71 return false;
72 }
73 break;
74 case GrPathRendering::kTranslateX_PathTransformType:
75 if (this->fDraws.head()->fY != that->fDraws.head()->fY) {
76 return false;
77 }
78 break;
79 case GrPathRendering::kTranslateY_PathTransformType:
80 if (this->fDraws.head()->fX != that->fDraws.head()->fX) {
81 return false;
82 }
83 break;
84 default: break;
bsalomon1fcc01c2015-09-09 09:48:06 -070085 }
86 // TODO: Check some other things here. (winding, opaque, pathProc color, vm, ...)
87 // Try to combine this call with the previous DrawPaths. We do this by stenciling all the
88 // paths together and then covering them in a single pass. This is not equivalent to two
89 // separate draw calls, so we can only do it if there is no blending (no overlap would also
90 // work). Note that it's also possible for overlapping paths to cancel each other's winding
91 // numbers, and we only partially account for this by not allowing even/odd paths to be
92 // combined. (Glyphs in the same font tend to wind the same direction so it works out OK.)
cdalton8ff8d242015-12-08 10:20:32 -080093 if (GrPathRendering::kWinding_FillType != this->fillType() ||
bsalomon1fcc01c2015-09-09 09:48:06 -070094 this->stencilSettings() != that->stencilSettings() ||
ethannicholasff210322015-11-24 12:10:10 -080095 this->overrides().willColorBlendWithDst()) {
bsalomon1fcc01c2015-09-09 09:48:06 -070096 return false;
97 }
ethannicholasff210322015-11-24 12:10:10 -080098 SkASSERT(!that->overrides().willColorBlendWithDst());
bsalomon1fcc01c2015-09-09 09:48:06 -070099 fTotalPathCount += that->fTotalPathCount;
cdaltoncdd46822015-12-08 10:48:31 -0800100 while (Draw* head = that->fDraws.head()) {
101 Draw* draw = fDraws.addToTail();
102 draw->fInstanceData.reset(head->fInstanceData.detach());
103 draw->fX = head->fX;
104 draw->fY = head->fY;
bsalomon1fcc01c2015-09-09 09:48:06 -0700105 that->fDraws.popHead();
106 }
107 return true;
108}
109
110void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) {
cdaltoncdd46822015-12-08 10:48:31 -0800111 const Draw& head = *fDraws.head();
112
113 SkMatrix drawMatrix(this->viewMatrix());
114 drawMatrix.preScale(fScale, fScale);
115 drawMatrix.preTranslate(head.fX, head.fY);
116
117 SkMatrix localMatrix;
118 localMatrix.setScale(fScale, fScale);
119 localMatrix.preTranslate(head.fX, head.fY);
120
joshualittf2384692015-09-10 11:00:51 -0700121 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
ethannicholasff210322015-11-24 12:10:10 -0800122 this->overrides(),
cdaltoncdd46822015-12-08 10:48:31 -0800123 drawMatrix,
124 localMatrix));
125
126 GrProgramDesc desc;
joshualitt465283c2015-09-11 08:19:35 -0700127 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline());
joshualittf2384692015-09-10 11:00:51 -0700128 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(),
cdaltoncdd46822015-12-08 10:48:31 -0800129 &desc, &this->stencilSettings());
130
bsalomon1fcc01c2015-09-09 09:48:06 -0700131 if (fDraws.count() == 1) {
cdaltoncdd46822015-12-08 10:48:31 -0800132 const InstanceData& instances = *head.fInstanceData;
133 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), instances.indices(),
134 GrPathRange::kU16_PathIndexType,
135 instances.transformValues(),
136 instances.transformType(),
137 instances.count());
138 } else {
139 int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType());
benjaminwagner67e8bd22016-02-02 16:01:39 -0800140#if defined(GOOGLE3)
141 //Stack frame size is limited in GOOGLE3.
142 SkAutoSTMalloc<512, float> transformStorage(floatsPerTransform * fTotalPathCount);
143 SkAutoSTMalloc<256, uint16_t> indexStorage(fTotalPathCount);
144#else
cdaltoncdd46822015-12-08 10:48:31 -0800145 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
146 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
benjaminwagner67e8bd22016-02-02 16:01:39 -0800147#endif
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(),
154 instances.count(),
155 draw.fX - head.fX, draw.fY - head.fY,
156 &transformStorage[floatsPerTransform * idx]);
157 idx += instances.count();
158
159 // TODO: Support mismatched transform types if we start using more types other than 2D.
160 SkASSERT(instances.transformType() == this->transformType());
161 }
162 SkASSERT(idx == fTotalPathCount);
163
164 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorage,
165 GrPathRange::kU16_PathIndexType, transformStorage,
166 this->transformType(), fTotalPathCount);
167 }
168}
169
170inline void pre_translate_transform_values(const float* xforms,
171 GrPathRendering::PathTransformType type, int count,
172 SkScalar x, SkScalar y, float* dst) {
173 if (0 == x && 0 == y) {
174 memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
bsalomon1fcc01c2015-09-09 09:48:06 -0700175 return;
176 }
cdaltoncdd46822015-12-08 10:48:31 -0800177 switch (type) {
178 case GrPathRendering::kNone_PathTransformType:
179 SkFAIL("Cannot pre-translate kNone_PathTransformType.");
180 break;
181 case GrPathRendering::kTranslateX_PathTransformType:
182 SkASSERT(0 == y);
183 for (int i = 0; i < count; i++) {
184 dst[i] = xforms[i] + x;
185 }
186 break;
187 case GrPathRendering::kTranslateY_PathTransformType:
188 SkASSERT(0 == x);
189 for (int i = 0; i < count; i++) {
190 dst[i] = xforms[i] + y;
191 }
192 break;
193 case GrPathRendering::kTranslate_PathTransformType:
194 for (int i = 0; i < 2 * count; i += 2) {
195 dst[i] = xforms[i] + x;
196 dst[i + 1] = xforms[i + 1] + y;
197 }
198 break;
199 case GrPathRendering::kAffine_PathTransformType:
200 for (int i = 0; i < 6 * count; i += 6) {
201 dst[i] = xforms[i];
202 dst[i + 1] = xforms[i + 1];
203 dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
204 dst[i + 3] = xforms[i + 3];
205 dst[i + 4] = xforms[i + 4];
206 dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
207 }
208 break;
209 default:
210 SkFAIL("Unknown transform type.");
211 break;
bsalomon1fcc01c2015-09-09 09:48:06 -0700212 }
bsalomon1fcc01c2015-09-09 09:48:06 -0700213}