OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrDrawPathBatch.h" | 8 #include "GrDrawPathBatch.h" |
9 | 9 |
| 10 static void pre_translate_transform_values(const float* xforms, |
| 11 GrPathRendering::PathTransformType ty
pe, int count, |
| 12 SkScalar x, SkScalar y, float* dst); |
| 13 |
10 SkString GrDrawPathBatch::dumpInfo() const { | 14 SkString GrDrawPathBatch::dumpInfo() const { |
11 SkString string; | 15 SkString string; |
12 string.printf("PATH: 0x%p", fPath.get()); | 16 string.printf("PATH: 0x%p", fPath.get()); |
13 return string; | 17 return string; |
14 } | 18 } |
15 | 19 |
16 void GrDrawPathBatch::onDraw(GrBatchFlushState* state) { | 20 void GrDrawPathBatch::onDraw(GrBatchFlushState* state) { |
17 GrProgramDesc desc; | 21 GrProgramDesc desc; |
18 | 22 |
19 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color()
, | 23 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color()
, |
20 this->overrid
es(), | 24 this->overrid
es(), |
21 this->viewMat
rix())); | 25 this->viewMat
rix())); |
22 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline()); | 26 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline()); |
23 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(), | 27 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(), |
24 &desc, &this->stencilSettings()); | 28 &desc, &this->stencilSettings()); |
25 state->gpu()->pathRendering()->drawPath(args, fPath.get()); | 29 state->gpu()->pathRendering()->drawPath(args, fPath.get()); |
26 } | 30 } |
27 | 31 |
28 GrDrawPathRangeBatch::~GrDrawPathRangeBatch() { | |
29 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { | |
30 (*iter.get())->unref(); | |
31 } | |
32 } | |
33 | |
34 SkString GrDrawPathRangeBatch::dumpInfo() const { | 32 SkString GrDrawPathRangeBatch::dumpInfo() const { |
35 SkString string; | 33 SkString string; |
36 string.printf("RANGE: 0x%p COUNTS: [", *fDraws.head()); | 34 string.printf("RANGE: 0x%p COUNTS: [", fPathRange.get()); |
37 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { | 35 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { |
38 string.appendf("%d ,", (*iter.get())->count()); | 36 string.appendf("%d, ", iter.get()->fInstanceData->count()); |
39 } | 37 } |
40 string.remove(string.size() - 2, 2); | 38 string.remove(string.size() - 2, 2); |
41 string.append("]"); | 39 string.append("]"); |
42 return string; | 40 return string; |
43 } | 41 } |
44 | 42 |
45 GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, const SkM
atrix& localMatrix, | 43 GrDrawPathRangeBatch::GrDrawPathRangeBatch(const SkMatrix& viewMatrix, SkScalar
scale, SkScalar x, |
46 GrColor color, GrPathRendering::FillT
ype fill, | 44 SkScalar y, GrColor color, |
47 GrPathRange* range, GrPathRangeDraw*
draw, | 45 GrPathRendering::FillType fill, GrPat
hRange* range, |
48 const SkRect& bounds) | 46 const InstanceData* instanceData, con
st SkRect& bounds) |
49 : INHERITED(ClassID(), viewMatrix, color, fill) | 47 : INHERITED(ClassID(), viewMatrix, color, fill) |
50 , fPathRange(range) | 48 , fPathRange(range) |
51 , fLocalMatrix(localMatrix) { | 49 , fTotalPathCount(instanceData->count()) |
52 SkDEBUGCODE(draw->fUsedInBatch = true;) | 50 , fScale(scale) { |
53 fDraws.addToHead(SkRef(draw)); | 51 fDraws.addToHead()->set(instanceData, x, y); |
54 fTotalPathCount = draw->count(); | |
55 fBounds = bounds; | 52 fBounds = bounds; |
56 } | 53 } |
57 | 54 |
58 bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { | 55 bool GrDrawPathRangeBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) { |
59 GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>(); | 56 GrDrawPathRangeBatch* that = t->cast<GrDrawPathRangeBatch>(); |
60 if (this->fPathRange.get() != that->fPathRange.get()) { | 57 if (this->fPathRange.get() != that->fPathRange.get() || |
61 return false; | 58 this->transformType() != that->transformType() || |
62 } | 59 this->fScale != that->fScale || |
63 if (!GrPathRangeDraw::CanMerge(**this->fDraws.head(), **that->fDraws.head())
) { | 60 this->color() != that->color() || |
| 61 !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
64 return false; | 62 return false; |
65 } | 63 } |
66 if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline(), false)) { | 64 if (!GrPipeline::AreEqual(*this->pipeline(), *that->pipeline(), false)) { |
67 return false; | 65 return false; |
68 } | 66 } |
69 if (this->color() != that->color() || | 67 switch (fDraws.head()->fInstanceData->transformType()) { |
70 !this->viewMatrix().cheapEqualTo(that->viewMatrix()) || | 68 case GrPathRendering::kNone_PathTransformType: |
71 !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) { | 69 if (this->fDraws.head()->fX != that->fDraws.head()->fX || |
72 return false; | 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; |
73 } | 85 } |
74 // TODO: Check some other things here. (winding, opaque, pathProc color, vm,
...) | 86 // TODO: Check some other things here. (winding, opaque, pathProc color, vm,
...) |
75 // Try to combine this call with the previous DrawPaths. We do this by stenc
iling all the | 87 // Try to combine this call with the previous DrawPaths. We do this by stenc
iling all the |
76 // paths together and then covering them in a single pass. This is not equiv
alent to two | 88 // paths together and then covering them in a single pass. This is not equiv
alent to two |
77 // separate draw calls, so we can only do it if there is no blending (no ove
rlap would also | 89 // separate draw calls, so we can only do it if there is no blending (no ove
rlap would also |
78 // work). Note that it's also possible for overlapping paths to cancel each
other's winding | 90 // work). Note that it's also possible for overlapping paths to cancel each
other's winding |
79 // numbers, and we only partially account for this by not allowing even/odd
paths to be | 91 // numbers, and we only partially account for this by not allowing even/odd
paths to be |
80 // combined. (Glyphs in the same font tend to wind the same direction so it
works out OK.) | 92 // combined. (Glyphs in the same font tend to wind the same direction so it
works out OK.) |
81 if (GrPathRendering::kWinding_FillType != this->fillType() || | 93 if (GrPathRendering::kWinding_FillType != this->fillType() || |
82 this->stencilSettings() != that->stencilSettings() || | 94 this->stencilSettings() != that->stencilSettings() || |
83 this->overrides().willColorBlendWithDst()) { | 95 this->overrides().willColorBlendWithDst()) { |
84 return false; | 96 return false; |
85 } | 97 } |
86 SkASSERT(!that->overrides().willColorBlendWithDst()); | 98 SkASSERT(!that->overrides().willColorBlendWithDst()); |
87 fTotalPathCount += that->fTotalPathCount; | 99 fTotalPathCount += that->fTotalPathCount; |
88 while (GrPathRangeDraw** head = that->fDraws.head()) { | 100 while (Draw* head = that->fDraws.head()) { |
89 fDraws.addToTail(*head); | 101 Draw* draw = fDraws.addToTail(); |
90 // We're stealing that's refs, so pop without unreffing. | 102 draw->fInstanceData.reset(head->fInstanceData.detach()); |
| 103 draw->fX = head->fX; |
| 104 draw->fY = head->fY; |
91 that->fDraws.popHead(); | 105 that->fDraws.popHead(); |
92 } | 106 } |
93 return true; | 107 return true; |
94 } | 108 } |
95 | 109 |
96 void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { | 110 void GrDrawPathRangeBatch::onDraw(GrBatchFlushState* state) { |
97 GrProgramDesc desc; | 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 |
98 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color()
, | 121 SkAutoTUnref<GrPathProcessor> pathProc(GrPathProcessor::Create(this->color()
, |
99 this->overrid
es(), | 122 this->overrid
es(), |
100 this->viewMat
rix(), | 123 drawMatrix, |
101 fLocalMatrix)
); | 124 localMatrix))
; |
| 125 |
| 126 GrProgramDesc desc; |
102 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline()); | 127 state->gpu()->buildProgramDesc(&desc, *pathProc, *this->pipeline()); |
103 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(), | 128 GrPathRendering::DrawPathArgs args(pathProc, this->pipeline(), |
104 &desc, &this->stencilSettings()); | 129 &desc, &this->stencilSettings()); |
| 130 |
105 if (fDraws.count() == 1) { | 131 if (fDraws.count() == 1) { |
106 const GrPathRangeDraw& draw = **fDraws.head(); | 132 const InstanceData& instances = *head.fInstanceData; |
107 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), draw.in
dices(), | 133 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), instanc
es.indices(), |
108 GrPathRange::kU16_PathIndexType, draw.transforms(), draw.transformTy
pe(), | 134 GrPathRange::kU16_PathIndexType
, |
109 draw.count()); | 135 instances.transformValues(), |
| 136 instances.transformType(), |
| 137 instances.count()); |
| 138 } else { |
| 139 int floatsPerTransform = GrPathRendering::PathTransformSize(this->transf
ormType()); |
| 140 #if defined(GOOGLE3) |
| 141 //Stack frame size is limited in GOOGLE3. |
| 142 SkAutoSTMalloc<512, float> transformStorage(transformSize * fTotalPathCo
unt); |
| 143 SkAutoSTMalloc<256, uint16_t> indexStorage(fTotalPathCount); |
| 144 #else |
| 145 SkAutoSTMalloc<4096, float> transformStorage(floatsPerTransform * fTotal
PathCount); |
| 146 SkAutoSTMalloc<2048, uint16_t> indexStorage(fTotalPathCount); |
| 147 #endif |
| 148 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->tr
ansformType(), |
| 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 t
ypes other than 2D. |
| 160 SkASSERT(instances.transformType() == this->transformType()); |
| 161 } |
| 162 SkASSERT(idx == fTotalPathCount); |
| 163 |
| 164 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexSt
orage, |
| 165 GrPathRange::kU16_PathIndexType
, transformStorage, |
| 166 this->transformType(), fTotalPa
thCount); |
| 167 } |
| 168 } |
| 169 |
| 170 inline void pre_translate_transform_values(const float* xforms, |
| 171 GrPathRendering::PathTransformType ty
pe, int count, |
| 172 SkScalar x, SkScalar y, float* dst) { |
| 173 if (0 == x && 0 == y) { |
| 174 memcpy(dst, xforms, count * GrPathRendering::PathTransformSize(type) * s
izeof(float)); |
110 return; | 175 return; |
111 } | 176 } |
112 | 177 switch (type) { |
113 GrPathRendering::PathTransformType transformType = (*fDraws.head())->transfo
rmType(); | 178 case GrPathRendering::kNone_PathTransformType: |
114 int floatsPerTransform = GrPathRendering::PathTransformSize(transformType); | 179 SkFAIL("Cannot pre-translate kNone_PathTransformType."); |
115 SkAutoSTMalloc<512, float> transformStorage(floatsPerTransform * fTotalPathC
ount); | 180 break; |
116 SkAutoSTMalloc<256, uint16_t> indexStorage(fTotalPathCount); | 181 case GrPathRendering::kTranslateX_PathTransformType: |
117 uint16_t* indices = indexStorage.get(); | 182 SkASSERT(0 == y); |
118 float* transforms = transformStorage.get(); | 183 for (int i = 0; i < count; i++) { |
119 for (DrawList::Iter iter(fDraws); iter.get(); iter.next()) { | 184 dst[i] = xforms[i] + x; |
120 SkASSERT((*iter.get())->transformType() == transformType); | 185 } |
121 int cnt = (*iter.get())->count(); | 186 break; |
122 memcpy(indices, (*iter.get())->indices(), cnt * sizeof(uint16_t)); | 187 case GrPathRendering::kTranslateY_PathTransformType: |
123 indices += cnt; | 188 SkASSERT(0 == x); |
124 memcpy(transforms, (*iter.get())->transforms(), cnt * floatsPerTransform
* sizeof(float)); | 189 for (int i = 0; i < count; i++) { |
125 transforms += cnt * floatsPerTransform; | 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; |
126 } | 212 } |
127 SkASSERT(indices - indexStorage.get() == fTotalPathCount); | |
128 state->gpu()->pathRendering()->drawPaths(args, fPathRange.get(), indexStorag
e.get(), | |
129 GrPathRange::kU16_PathIndexType, transformStorage.get(), transformType, | |
130 fTotalPathCount); | |
131 } | 213 } |
OLD | NEW |