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 "GrNonAAStrokeRectBatch.h" | 8 #include "GrNonAAStrokeRectBatch.h" |
9 | 9 |
10 #include "GrBatchTest.h" | 10 #include "GrBatchTest.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 verts[2].set(rect.fRight - rad, rect.fTop + rad); | 30 verts[2].set(rect.fRight - rad, rect.fTop + rad); |
31 verts[3].set(rect.fRight + rad, rect.fTop - rad); | 31 verts[3].set(rect.fRight + rad, rect.fTop - rad); |
32 verts[4].set(rect.fRight - rad, rect.fBottom - rad); | 32 verts[4].set(rect.fRight - rad, rect.fBottom - rad); |
33 verts[5].set(rect.fRight + rad, rect.fBottom + rad); | 33 verts[5].set(rect.fRight + rad, rect.fBottom + rad); |
34 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); | 34 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); |
35 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); | 35 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); |
36 verts[8] = verts[0]; | 36 verts[8] = verts[0]; |
37 verts[9] = verts[1]; | 37 verts[9] = verts[1]; |
38 } | 38 } |
39 | 39 |
| 40 // Allow all hairlines and all miters, so long as the miter limit doesn't produc
e beveled corners. |
| 41 inline static bool allowed_stroke(const SkStrokeRec& stroke) { |
| 42 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || |
| 43 stroke.getStyle() == SkStrokeRec::kHairline_Style); |
| 44 return !stroke.getWidth() || |
| 45 (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_S
calarSqrt2); |
| 46 } |
| 47 |
40 class NonAAStrokeRectBatch : public GrVertexBatch { | 48 class NonAAStrokeRectBatch : public GrVertexBatch { |
41 public: | 49 public: |
42 DEFINE_BATCH_CLASS_ID | 50 DEFINE_BATCH_CLASS_ID |
43 | 51 |
44 struct Geometry { | 52 const char* name() const override { return "NonAAStrokeRectBatch"; } |
45 SkMatrix fViewMatrix; | |
46 SkRect fRect; | |
47 SkScalar fStrokeWidth; | |
48 GrColor fColor; | |
49 }; | |
50 | |
51 static NonAAStrokeRectBatch* Create() { | |
52 return new NonAAStrokeRectBatch; | |
53 } | |
54 | |
55 const char* name() const override { return "GrStrokeRectBatch"; } | |
56 | 53 |
57 void computePipelineOptimizations(GrInitInvariantOutput* color, | 54 void computePipelineOptimizations(GrInitInvariantOutput* color, |
58 GrInitInvariantOutput* coverage, | 55 GrInitInvariantOutput* coverage, |
59 GrBatchToXPOverrides* overrides) const ove
rride { | 56 GrBatchToXPOverrides* overrides) const ove
rride { |
60 // When this is called on a batch, there is only one geometry bundle | 57 // When this is called on a batch, there is only one geometry bundle |
61 color->setKnownFourComponents(fGeoData[0].fColor); | 58 color->setKnownFourComponents(fColor); |
62 coverage->setKnownSingleComponent(0xff); | 59 coverage->setKnownSingleComponent(0xff); |
63 } | 60 } |
64 | 61 |
65 void append(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, | 62 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const
SkRect& rect, |
66 SkScalar strokeWidth) { | 63 const SkStrokeRec& stroke, bool snapToPixelCenter
s) { |
67 Geometry& geometry = fGeoData.push_back(); | 64 if (!allowed_stroke(stroke)) { |
68 geometry.fViewMatrix = viewMatrix; | 65 return nullptr; |
69 geometry.fRect = rect; | 66 } |
70 geometry.fStrokeWidth = strokeWidth; | 67 NonAAStrokeRectBatch* batch = new NonAAStrokeRectBatch(); |
71 geometry.fColor = color; | 68 batch->fColor = color; |
| 69 batch->fViewMatrix = viewMatrix; |
| 70 batch->fRect = rect; |
| 71 // Sort the rect for hairlines |
| 72 batch->fRect.sort(); |
| 73 batch->fStrokeWidth = stroke.getWidth(); |
72 | 74 |
73 // Sort the rect for hairlines | 75 batch->fBounds = batch->fRect; |
74 geometry.fRect.sort(); | 76 SkScalar rad = SkScalarHalf(batch->fStrokeWidth); |
75 } | 77 batch->fBounds.outset(rad, rad); |
76 | 78 batch->fViewMatrix.mapRect(&batch->fBounds); |
77 void appendAndUpdateBounds(GrColor color, const SkMatrix& viewMatrix, const
SkRect& rect, | |
78 SkScalar strokeWidth, bool snapToPixelCenters) { | |
79 this->append(color, viewMatrix, rect, strokeWidth); | |
80 | |
81 SkRect bounds; | |
82 this->setupBounds(&bounds, fGeoData.back(), snapToPixelCenters); | |
83 this->joinBounds(bounds); | |
84 } | |
85 | |
86 void init(bool snapToPixelCenters) { | |
87 const Geometry& geo = fGeoData[0]; | |
88 fBatch.fHairline = geo.fStrokeWidth == 0; | |
89 | |
90 // setup bounds | |
91 this->setupBounds(&fBounds, geo, snapToPixelCenters); | |
92 } | |
93 | |
94 private: | |
95 void setupBounds(SkRect* bounds, const Geometry& geo, bool snapToPixelCenter
s) { | |
96 *bounds = geo.fRect; | |
97 SkScalar rad = SkScalarHalf(geo.fStrokeWidth); | |
98 bounds->outset(rad, rad); | |
99 geo.fViewMatrix.mapRect(&fBounds); | |
100 | 79 |
101 // If our caller snaps to pixel centers then we have to round out the bo
unds | 80 // If our caller snaps to pixel centers then we have to round out the bo
unds |
102 if (snapToPixelCenters) { | 81 if (snapToPixelCenters) { |
103 // We want to be consistent with how we snap non-aa lines. To match
what we do in | 82 // We want to be consistent with how we snap non-aa lines. To match
what we do in |
104 // GrGLSLVertexShaderBuilder, we first floor all the vertex values a
nd then add half a | 83 // GrGLSLVertexShaderBuilder, we first floor all the vertex values a
nd then add half a |
105 // pixel to force us to pixel centers. | 84 // pixel to force us to pixel centers. |
106 bounds->set(SkScalarFloorToScalar(bounds->fLeft), | 85 batch->fBounds.set(SkScalarFloorToScalar(batch->fBounds.fLeft), |
107 SkScalarFloorToScalar(bounds->fTop), | 86 SkScalarFloorToScalar(batch->fBounds.fTop), |
108 SkScalarFloorToScalar(bounds->fRight), | 87 SkScalarFloorToScalar(batch->fBounds.fRight), |
109 SkScalarFloorToScalar(bounds->fBottom)); | 88 SkScalarFloorToScalar(batch->fBounds.fBottom)); |
110 bounds->offset(0.5f, 0.5f); | 89 batch->fBounds.offset(0.5f, 0.5f); |
111 | 90 |
112 // Round out the bounds to integer values | 91 // Round out the bounds to integer values |
113 bounds->roundOut(); | 92 batch->fBounds.roundOut(); |
114 } | 93 } |
| 94 return batch; |
115 } | 95 } |
116 | 96 |
| 97 private: |
| 98 NonAAStrokeRectBatch() : INHERITED(ClassID()) {} |
| 99 |
117 void onPrepareDraws(Target* target) const override { | 100 void onPrepareDraws(Target* target) const override { |
118 sk_sp<GrGeometryProcessor> gp; | 101 sk_sp<GrGeometryProcessor> gp; |
119 { | 102 { |
120 using namespace GrDefaultGeoProcFactory; | 103 using namespace GrDefaultGeoProcFactory; |
121 Color color(this->color()); | 104 Color color(fColor); |
122 Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type : | 105 Coverage coverage(fOverrides.readsCoverage() ? Coverage::kSolid_Type |
123 Coverage::kNone_Type); | 106 : Coverage::kNone_Type)
; |
124 LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUseP
osition_Type : | 107 LocalCoords localCoords(fOverrides.readsLocalCoords() ? LocalCoords:
:kUsePosition_Type : |
125 LocalCoords::kUnus
ed_Type); | 108 LocalCoords:
:kUnused_Type); |
126 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, thi
s->viewMatrix()); | 109 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fVi
ewMatrix); |
127 } | 110 } |
128 | 111 |
129 size_t vertexStride = gp->getVertexStride(); | 112 size_t vertexStride = gp->getVertexStride(); |
130 | 113 |
131 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); | 114 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); |
132 | 115 |
133 const Geometry& args = fGeoData[0]; | |
134 | |
135 int vertexCount = kVertsPerHairlineRect; | 116 int vertexCount = kVertsPerHairlineRect; |
136 if (args.fStrokeWidth > 0) { | 117 if (fStrokeWidth > 0) { |
137 vertexCount = kVertsPerStrokeRect; | 118 vertexCount = kVertsPerStrokeRect; |
138 } | 119 } |
139 | 120 |
140 const GrBuffer* vertexBuffer; | 121 const GrBuffer* vertexBuffer; |
141 int firstVertex; | 122 int firstVertex; |
142 | 123 |
143 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex
Buffer, | 124 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex
Buffer, |
144 &firstVertex); | 125 &firstVertex); |
145 | 126 |
146 if (!verts) { | 127 if (!verts) { |
147 SkDebugf("Could not allocate vertices\n"); | 128 SkDebugf("Could not allocate vertices\n"); |
148 return; | 129 return; |
149 } | 130 } |
150 | 131 |
151 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); | 132 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); |
152 | 133 |
153 GrPrimitiveType primType; | 134 GrPrimitiveType primType; |
154 if (args.fStrokeWidth > 0) { | 135 if (fStrokeWidth > 0) { |
155 primType = kTriangleStrip_GrPrimitiveType; | 136 primType = kTriangleStrip_GrPrimitiveType; |
156 init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth); | 137 init_stroke_rect_strip(vertex, fRect, fStrokeWidth); |
157 } else { | 138 } else { |
158 // hairline | 139 // hairline |
159 primType = kLineStrip_GrPrimitiveType; | 140 primType = kLineStrip_GrPrimitiveType; |
160 vertex[0].set(args.fRect.fLeft, args.fRect.fTop); | 141 vertex[0].set(fRect.fLeft, fRect.fTop); |
161 vertex[1].set(args.fRect.fRight, args.fRect.fTop); | 142 vertex[1].set(fRect.fRight, fRect.fTop); |
162 vertex[2].set(args.fRect.fRight, args.fRect.fBottom); | 143 vertex[2].set(fRect.fRight, fRect.fBottom); |
163 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); | 144 vertex[3].set(fRect.fLeft, fRect.fBottom); |
164 vertex[4].set(args.fRect.fLeft, args.fRect.fTop); | 145 vertex[4].set(fRect.fLeft, fRect.fTop); |
165 } | 146 } |
166 | 147 |
167 GrMesh mesh; | 148 GrMesh mesh; |
168 mesh.init(primType, vertexBuffer, firstVertex, vertexCount); | 149 mesh.init(primType, vertexBuffer, firstVertex, vertexCount); |
169 target->draw(gp.get(), mesh); | 150 target->draw(gp.get(), mesh); |
170 } | 151 } |
171 | 152 |
172 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 153 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
173 // Handle any color overrides | 154 overrides.getOverrideColorIfSet(&fColor); |
174 if (!overrides.readsColor()) { | 155 fOverrides = overrides; |
175 fGeoData[0].fColor = GrColor_ILLEGAL; | |
176 } | |
177 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | |
178 | |
179 // setup batch properties | |
180 fBatch.fColorIgnored = !overrides.readsColor(); | |
181 fBatch.fColor = fGeoData[0].fColor; | |
182 fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); | |
183 fBatch.fCoverageIgnored = !overrides.readsCoverage(); | |
184 } | 156 } |
185 | 157 |
186 NonAAStrokeRectBatch() : INHERITED(ClassID()) {} | |
187 | |
188 GrColor color() const { return fBatch.fColor; } | |
189 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
190 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
191 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
192 bool hairline() const { return fBatch.fHairline; } | |
193 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
194 | |
195 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { | 158 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { |
196 // if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *t->pi
peline(), | |
197 // t->bounds(), caps)) { | |
198 // return false; | |
199 // } | |
200 // GrStrokeRectBatch* that = t->cast<StrokeRectBatch>(); | |
201 | |
202 // NonAA stroke rects cannot batch right now | 159 // NonAA stroke rects cannot batch right now |
203 // TODO make these batchable | 160 // TODO make these batchable |
204 return false; | 161 return false; |
205 } | 162 } |
206 | 163 |
207 struct BatchTracker { | 164 GrColor fColor; |
208 GrColor fColor; | 165 SkMatrix fViewMatrix; |
209 bool fUsesLocalCoords; | 166 SkRect fRect; |
210 bool fColorIgnored; | 167 SkScalar fStrokeWidth; |
211 bool fCoverageIgnored; | 168 |
212 bool fHairline; | 169 GrXPOverridesForBatch fOverrides; |
213 }; | |
214 | 170 |
215 const static int kVertsPerHairlineRect = 5; | 171 const static int kVertsPerHairlineRect = 5; |
216 const static int kVertsPerStrokeRect = 10; | 172 const static int kVertsPerStrokeRect = 10; |
217 | 173 |
218 BatchTracker fBatch; | |
219 SkSTArray<1, Geometry, true> fGeoData; | |
220 | 174 |
221 typedef GrVertexBatch INHERITED; | 175 typedef GrVertexBatch INHERITED; |
222 }; | 176 }; |
223 | 177 |
224 // Allow all hairlines and all miters, so long as the miter limit doesn't produc
e beveled corners. | |
225 inline static bool allowed_stroke(const SkStrokeRec& stroke) { | |
226 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || | |
227 stroke.getStyle() == SkStrokeRec::kHairline_Style); | |
228 return !stroke.getWidth() || | |
229 (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_
ScalarSqrt2); | |
230 } | |
231 | |
232 namespace GrNonAAStrokeRectBatch { | 178 namespace GrNonAAStrokeRectBatch { |
233 | 179 |
234 GrDrawBatch* Create(GrColor color, | 180 GrDrawBatch* Create(GrColor color, |
235 const SkMatrix& viewMatrix, | 181 const SkMatrix& viewMatrix, |
236 const SkRect& rect, | 182 const SkRect& rect, |
237 const SkStrokeRec& stroke, | 183 const SkStrokeRec& stroke, |
238 bool snapToPixelCenters) { | 184 bool snapToPixelCenters) { |
239 if (!allowed_stroke(stroke)) { | 185 return NonAAStrokeRectBatch::Create(color, viewMatrix, rect, stroke, snapToP
ixelCenters); |
240 return nullptr; | |
241 } | |
242 NonAAStrokeRectBatch* batch = NonAAStrokeRectBatch::Create(); | |
243 batch->append(color, viewMatrix, rect, stroke.getWidth()); | |
244 batch->init(snapToPixelCenters); | |
245 return batch; | |
246 } | 186 } |
247 | 187 |
248 }; | 188 } |
249 | 189 |
250 #ifdef GR_TEST_UTILS | 190 #ifdef GR_TEST_UTILS |
251 | 191 |
252 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { | 192 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { |
253 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 193 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
254 GrColor color = GrRandomColor(random); | 194 GrColor color = GrRandomColor(random); |
255 SkRect rect = GrTest::TestRect(random); | 195 SkRect rect = GrTest::TestRect(random); |
256 SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f; | 196 SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f; |
257 SkPaint paint; | 197 SkPaint paint; |
258 paint.setStrokeWidth(strokeWidth); | 198 paint.setStrokeWidth(strokeWidth); |
259 paint.setStyle(SkPaint::kStroke_Style); | 199 paint.setStyle(SkPaint::kStroke_Style); |
260 paint.setStrokeJoin(SkPaint::kMiter_Join); | 200 paint.setStrokeJoin(SkPaint::kMiter_Join); |
261 SkStrokeRec strokeRec(paint); | 201 SkStrokeRec strokeRec(paint); |
262 return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, ra
ndom->nextBool()); | 202 return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, ra
ndom->nextBool()); |
263 } | 203 } |
264 | 204 |
265 #endif | 205 #endif |
OLD | NEW |