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 #include "GrRenderTargetPriv.h"
11
12 static void pre_translate_transform_values(const float* xforms,
13 GrPathRendering::PathTransformType type, int count,
14 SkScalar x, SkScalar y, float* dst);
15
onPrepare(GrBatchFlushState *)16 void GrDrawPathBatchBase::onPrepare(GrBatchFlushState*) {
17 const GrRenderTargetPriv& rtPriv = this->pipeline()->getRenderTarget()->renderTargetPriv();
18 fStencilPassSettings.reset(GrPathRendering::GetStencilPassSettings(fFillType),
19 this->pipeline()->hasStencilClip(), rtPriv.numStencilBits());
20 }
21
dumpInfo() const22 SkString GrDrawPathBatch::dumpInfo() const {
23 SkString string;
24 string.printf("PATH: 0x%p", fPath.get());
25 string.append(INHERITED::dumpInfo());
26 return string;
27 }
28
onDraw(GrBatchFlushState * state)29 void GrDrawPathBatch::onDraw(GrBatchFlushState* state) {
30 GrProgramDesc desc;
31
32 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
33 this->overrides(),
34 this->viewMatrix()));
35 state->gpu()->pathRendering()->drawPath(*this->pipeline(), *pathProc,
36 this->stencilPassSettings(), fPath.get());
37 }
38
dumpInfo() const39 SkString GrDrawPathRangeBatch::dumpInfo() const {
40 SkString string;
41 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get());
42 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
43 string.appendf("%d, ", iter.get()->fInstanceData->count());
44 }
45 string.remove(string.size() - 2, 2);
46 string.append("]");
47 string.append(INHERITED::dumpInfo());
48 return string;
49 }
50
GrDrawPathRangeBatch(const SkMatrix & viewMatrix,SkScalar scale,SkScalar x,SkScalar y,GrColor color,GrPathRendering::FillType fill,GrPathRange * range,const InstanceData * instanceData,const SkRect & bounds)51 GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar scale, SkScalar x,
52 SkScalar y, GrColor color,
53 GrPathRendering::FillType fill, GrPathRange* range,
54 const InstanceData* instanceData, const SkRect& bounds)
55 : INHERITED(ClassID(), viewMatrix, color, fill)
56 , fPathRange(range)
57 , fTotalPathCount(instanceData->count())
58 , fScale(scale) {
59 fDraws.addToHead()->set(instanceData, x, y);
60 this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
61 }
62
onCombineIfPossible(GrBatch * t,const GrCaps & caps)63 bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
64 GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>();
65 if (this->fPathRange.get() != that->fPathRange.get() ||
66 this->transformType() != that->transformType() ||
67 this->fScale != that->fScale ||
68 this->color() != that->color() ||
69 !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
70 return false;
71 }
72 if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline())) {
73 return false;
74 }
75 switch (fDraws.head()->fInstanceData->transformType()) {
76 case GrPathRendering::kNone_PathTransformType:
77 if (this->fDraws.head()->fX != that->fDraws.head()->fX ||
78 this->fDraws.head()->fY != that->fDraws.head()->fY) {
79 return false;
80 }
81 break;
82 case GrPathRendering::kTranslateX_PathTransformType:
83 if (this->fDraws.head()->fY != that->fDraws.head()->fY) {
84 return false;
85 }
86 break;
87 case GrPathRendering::kTranslateY_PathTransformType:
88 if (this->fDraws.head()->fX != that->fDraws.head()->fX) {
89 return false;
90 }
91 break;
92 default: break;
93 }
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.)
101 if (GrPathRendering::kWinding_FillType != this->fillType() ||
102 GrPathRendering::kWinding_FillType != that->fillType() ||
103 this->overrides().willColorBlendWithDst()) {
104 return false;
105 }
106 SkASSERT(!that->overrides().willColorBlendWithDst());
107 fTotalPathCount += that->fTotalPathCount;
108 while (Draw* head = that->fDraws.head()) {
109 Draw* draw = fDraws.addToTail();
110 draw->fInstanceData.reset(head->fInstanceData.release());
111 draw->fX = head->fX;
112 draw->fY = head->fY;
113 that->fDraws.popHead();
114 }
115 this->joinBounds(*that);
116 return true;
117 }
118
onDraw(GrBatchFlushState * state)119 void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) {
120 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
130 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color(),
131 this->overrides(),
132 drawMatrix,
133 localMatrix));
134
135 if (fDraws.count() == 1) {
136 const InstanceData& instances = *head.fInstanceData;
137 state->gpu()->pathRendering()->drawPaths(*this->pipeline(),
138 *pathProc,
139 this->stencilPassSettings(),
140 fPathRange.get(),
141 instances.indices(),
142 GrPathRange::kU16_PathIndexType,
143 instances.transformValues(),
144 instances.transformType(),
145 instances.count());
146 } else {
147 int floatsPerTransform = GrPathRendering::PathTransformSize(this->transformType());
148 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotalPathCount);
149 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount);
150 int idx = 0;
151 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) {
152 const Draw& draw = *iter.get();
153 const InstanceData& instances = *draw.fInstanceData;
154 memcpy(&indexStorage[idx], instances.indices(), instances.count() * sizeof(uint16_t));
155 pre_translate_transform_values(instances.transformValues(), this->transformType(),
156 instances.count(),
157 draw.fX - head.fX, draw.fY - head.fY,
158 &transformStorage[floatsPerTransform * idx]);
159 idx += instances.count();
160
161 // TODO: Support mismatched transform types if we start using more types other than 2D.
162 SkASSERT(instances.transformType() == this->transformType());
163 }
164 SkASSERT(idx == fTotalPathCount);
165
166 state->gpu()->pathRendering()->drawPaths(*this->pipeline(),
167 *pathProc,
168 this->stencilPassSettings(),
169 fPathRange.get(),
170 indexStorage,
171 GrPathRange::kU16_PathIndexType,
172 transformStorage,
173 this->transformType(),
174 fTotalPathCount);
175 }
176 }
177
pre_translate_transform_values(const float * xforms,GrPathRendering::PathTransformType type,int count,SkScalar x,SkScalar y,float * dst)178 inline void pre_translate_transform_values(const float* xforms,
179 GrPathRendering::PathTransformType type, int count,
180 SkScalar x, SkScalar y, float* dst) {
181 if (0 == x && 0 == y) {
182 memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * sizeof(float));
183 return;
184 }
185 switch (type) {
186 case GrPathRendering::kNone_PathTransformType:
187 SkFAIL("Cannot pre-translate kNone_PathTransformType.");
188 break;
189 case GrPathRendering::kTranslateX_PathTransformType:
190 SkASSERT(0 == y);
191 for (int i = 0; i < count; i++) {
192 dst[i] = xforms[i] + x;
193 }
194 break;
195 case GrPathRendering::kTranslateY_PathTransformType:
196 SkASSERT(0 == x);
197 for (int i = 0; i < count; i++) {
198 dst[i] = xforms[i] + y;
199 }
200 break;
201 case GrPathRendering::kTranslate_PathTransformType:
202 for (int i = 0; i < 2 * count; i += 2) {
203 dst[i] = xforms[i] + x;
204 dst[i + 1] = xforms[i + 1] + y;
205 }
206 break;
207 case GrPathRendering::kAffine_PathTransformType:
208 for (int i = 0; i < 6 * count; i += 6) {
209 dst[i] = xforms[i];
210 dst[i + 1] = xforms[i + 1];
211 dst[i + 2] = xforms[i] * x + xforms[i + 1] * y + xforms[i + 2];
212 dst[i + 3] = xforms[i + 3];
213 dst[i + 4] = xforms[i + 4];
214 dst[i + 5] = xforms[i + 3] * x + xforms[i + 4] * y + xforms[i + 5];
215 }
216 break;
217 default:
218 SkFAIL("Unknown transform type.");
219 break;
220 }
221 }
222