• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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