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