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 "GrDrawPathBatch.h"
9
10 static void pre_translate_transform_values(const float* xforms,
11 GrPathRendering::PathTransformType type, int count,
12 SkScalar x, SkScalar y, float* dst);
13
dumpInfo() const14 SkString GrDrawPathBatch::dumpInfo() const {
15 SkString string;
16 string.printf("PATH: 0x%p", fPath.get());
17 return string;
18 }
19
onDraw(GrBatchFlushState * state)20 void GrDrawPathBatch::onDraw(GrBatchFlushState* state) {
21 GrProgramDesc desc;
22
23 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
24 this->overrides(),
25 this->viewMatrix()));
26 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline());
27 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(),
28 &desc, &this->stencilSettings());
29 state->gpu()->pathRendering()->drawPath(args, fPath.get());
30 }
31
dumpInfo() const32 SkString GrDrawPathRangeBatch::dumpInfo() const {
33 SkString string;
34 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
35 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
36 string.appendf("%d, ", iter.get()->fInstanceData->count());
37 }
38 string.remove(string.size() - 2, 2);
39 string.append("]");
40 return string;
41 }
42
GrDrawPathRangeBatch(const SkMatrix & viewMatrix,SkScalar scale,SkScalar x,SkScalar y,GrColor color,GrPathRendering::FillType fill,GrPathRange * range,const InstanceData * instanceData,const SkRect & bounds)43 GrDrawPathRangeBatch::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)
47 : INHERITED(ClassID(), viewMatrix, color, fill)
48 , fPathRange(range)
49 , fTotalPathCount(instanceData->count())
50 , fScale(scale) {
51 fDraws.addToHead()->set(instanceData, x, y);
52 fBounds = bounds;
53 }
54
onCombineIfPossible(GrBatch * t,const GrCaps & caps)55 bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
56 GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>();
57 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())) {
62 return false;
63 }
64 if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline(), false)) {
65 return false;
66 }
67 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;
85 }
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.)
93 if (GrPathRendering::kWinding_FillType != this->fillType() ||
94 this->stencilSettings() != that->stencilSettings() ||
95 this->overrides().willColorBlendWithDst()) {
96 return false;
97 }
98 SkASSERT(!that->overrides().willColorBlendWithDst());
99 fTotalPathCount += that->fTotalPathCount;
100 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;
105 that->fDraws.popHead();
106 }
107 return true;
108 }
109
onDraw(GrBatchFlushState * state)110 void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) {
111 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
121 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
122 this->overrides(),
123 drawMatrix,
124 localMatrix));
125
126 GrProgramDesc desc;
127 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline());
128 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(),
129 &desc, &this->stencilSettings());
130
131 if (fDraws.count() == 1) {
132 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());
140 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
141 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
142 int idx = 0;
143 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
144 const Draw& draw = *iter.get();
145 const InstanceData& instances = *draw.fInstanceData;
146 memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t));
147 pre_translate_transform_values(instances.transformValues(), this->transformType(),
148 instances.count(),
149 draw.fX - head.fX, draw.fY - head.fY,
150 &transformStorage[floatsPerTransform * idx]);
151 idx += instances.count();
152
153 // TODO: Support mismatched transform types if we start using more types other than 2D.
154 SkASSERT(instances.transformType() == this->transformType());
155 }
156 SkASSERT(idx == fTotalPathCount);
157
158 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorage,
159 GrPathRange::kU16_PathIndexType, transformStorage,
160 this->transformType(), fTotalPathCount);
161 }
162 }
163
pre_translate_transform_values(const float * xforms,GrPathRendering::PathTransformType type,int count,SkScalar x,SkScalar y,float * dst)164 inline void pre_translate_transform_values(const float* xforms,
165 GrPathRendering::PathTransformType type, int count,
166 SkScalar x, SkScalar y, float* dst) {
167 if (0 == x && 0 == y) {
168 memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
169 return;
170 }
171 switch (type) {
172 case GrPathRendering::kNone_PathTransformType:
173 SkFAIL("Cannot pre-translate kNone_PathTransformType.");
174 break;
175 case GrPathRendering::kTranslateX_PathTransformType:
176 SkASSERT(0 == y);
177 for (int i = 0; i < count; i++) {
178 dst[i] = xforms[i] + x;
179 }
180 break;
181 case GrPathRendering::kTranslateY_PathTransformType:
182 SkASSERT(0 == x);
183 for (int i = 0; i < count; i++) {
184 dst[i] = xforms[i] + y;
185 }
186 break;
187 case GrPathRendering::kTranslate_PathTransformType:
188 for (int i = 0; i < 2 * count; i += 2) {
189 dst[i] = xforms[i] + x;
190 dst[i + 1] = xforms[i + 1] + y;
191 }
192 break;
193 case GrPathRendering::kAffine_PathTransformType:
194 for (int i = 0; i < 6 * count; i += 6) {
195 dst[i] = xforms[i];
196 dst[i + 1] = xforms[i + 1];
197 dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
198 dst[i + 3] = xforms[i + 3];
199 dst[i + 4] = xforms[i + 4];
200 dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
201 }
202 break;
203 default:
204 SkFAIL("Unknown transform type.");
205 break;
206 }
207 }
208