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); |
78 batch->fViewMatrix.mapRect(&batch->fBounds); | |
76 | 79 |
77 void appendAndUpdateBounds(GrColor color, const SkMatrix& viewMatrix, const SkRect& rect, | 80 // If our caller snaps to pixel centers then we have to round out the bo unds |
78 SkScalar strokeWidth, bool snapToPixelCenters) { | 81 if (snapToPixelCenters) { |
robertphillips
2016/07/06 20:44:06
Greg just posted a CL that changes this code: http
| |
79 this->append(color, viewMatrix, rect, strokeWidth); | 82 batch->fBounds.roundOut(); |
80 | 83 } |
81 SkRect bounds; | 84 return batch; |
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 } | 85 } |
93 | 86 |
94 private: | 87 private: |
95 void setupBounds(SkRect* bounds, const Geometry& geo, bool snapToPixelCenter s) { | 88 NonAAStrokeRectBatch() : INHERITED(ClassID()) {} |
96 *bounds = geo.fRect; | |
97 SkScalar rad = SkScalarHalf(geo.fStrokeWidth); | |
98 bounds->outset(rad, rad); | |
99 geo.fViewMatrix.mapRect(&fBounds); | |
100 | |
101 // If our caller snaps to pixel centers then we have to round out the bo unds | |
102 if (snapToPixelCenters) { | |
103 bounds->roundOut(); | |
104 } | |
105 } | |
106 | 89 |
107 void onPrepareDraws(Target* target) const override { | 90 void onPrepareDraws(Target* target) const override { |
108 sk_sp<GrGeometryProcessor> gp; | 91 sk_sp<GrGeometryProcessor> gp; |
109 { | 92 { |
110 using namespace GrDefaultGeoProcFactory; | 93 using namespace GrDefaultGeoProcFactory; |
111 Color color(this->color()); | 94 Color color(fColor); |
112 Coverage coverage(this->coverageIgnored() ? Coverage::kSolid_Type : | 95 Coverage coverage(fOverrides.readsCoverage() ? Coverage::kSolid_Type |
113 Coverage::kNone_Type); | 96 : Coverage::kNone_Type) ; |
114 LocalCoords localCoords(this->usesLocalCoords() ? LocalCoords::kUseP osition_Type : | 97 LocalCoords localCoords(fOverrides.readsLocalCoords() ? LocalCoords: :kUsePosition_Type : |
115 LocalCoords::kUnus ed_Type); | 98 LocalCoords: :kUnused_Type); |
116 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, thi s->viewMatrix()); | 99 gp = GrDefaultGeoProcFactory::Make(color, coverage, localCoords, fVi ewMatrix); |
117 } | 100 } |
118 | 101 |
119 size_t vertexStride = gp->getVertexStride(); | 102 size_t vertexStride = gp->getVertexStride(); |
120 | 103 |
121 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); | 104 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr)); |
122 | 105 |
123 const Geometry& args = fGeoData[0]; | |
124 | |
125 int vertexCount = kVertsPerHairlineRect; | 106 int vertexCount = kVertsPerHairlineRect; |
126 if (args.fStrokeWidth > 0) { | 107 if (fStrokeWidth > 0) { |
127 vertexCount = kVertsPerStrokeRect; | 108 vertexCount = kVertsPerStrokeRect; |
128 } | 109 } |
129 | 110 |
130 const GrBuffer* vertexBuffer; | 111 const GrBuffer* vertexBuffer; |
131 int firstVertex; | 112 int firstVertex; |
132 | 113 |
133 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex Buffer, | 114 void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertex Buffer, |
134 &firstVertex); | 115 &firstVertex); |
135 | 116 |
136 if (!verts) { | 117 if (!verts) { |
137 SkDebugf("Could not allocate vertices\n"); | 118 SkDebugf("Could not allocate vertices\n"); |
138 return; | 119 return; |
139 } | 120 } |
140 | 121 |
141 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); | 122 SkPoint* vertex = reinterpret_cast<SkPoint*>(verts); |
142 | 123 |
143 GrPrimitiveType primType; | 124 GrPrimitiveType primType; |
144 if (args.fStrokeWidth > 0) { | 125 if (fStrokeWidth > 0) { |
145 primType = kTriangleStrip_GrPrimitiveType; | 126 primType = kTriangleStrip_GrPrimitiveType; |
146 init_stroke_rect_strip(vertex, args.fRect, args.fStrokeWidth); | 127 init_stroke_rect_strip(vertex, fRect, fStrokeWidth); |
147 } else { | 128 } else { |
148 // hairline | 129 // hairline |
149 primType = kLineStrip_GrPrimitiveType; | 130 primType = kLineStrip_GrPrimitiveType; |
150 vertex[0].set(args.fRect.fLeft, args.fRect.fTop); | 131 vertex[0].set(fRect.fLeft, fRect.fTop); |
151 vertex[1].set(args.fRect.fRight, args.fRect.fTop); | 132 vertex[1].set(fRect.fRight, fRect.fTop); |
152 vertex[2].set(args.fRect.fRight, args.fRect.fBottom); | 133 vertex[2].set(fRect.fRight, fRect.fBottom); |
153 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom); | 134 vertex[3].set(fRect.fLeft, fRect.fBottom); |
154 vertex[4].set(args.fRect.fLeft, args.fRect.fTop); | 135 vertex[4].set(fRect.fLeft, fRect.fTop); |
155 } | 136 } |
156 | 137 |
157 GrMesh mesh; | 138 GrMesh mesh; |
158 mesh.init(primType, vertexBuffer, firstVertex, vertexCount); | 139 mesh.init(primType, vertexBuffer, firstVertex, vertexCount); |
159 target->draw(gp.get(), mesh); | 140 target->draw(gp.get(), mesh); |
160 } | 141 } |
161 | 142 |
162 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 143 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
163 // Handle any color overrides | 144 overrides.getOverrideColorIfSet(&fColor); |
164 if (!overrides.readsColor()) { | 145 fOverrides = overrides; |
165 fGeoData[0].fColor = GrColor_ILLEGAL; | |
166 } | |
167 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | |
168 | |
169 // setup batch properties | |
170 fBatch.fColorIgnored = !overrides.readsColor(); | |
171 fBatch.fColor = fGeoData[0].fColor; | |
172 fBatch.fUsesLocalCoords = overrides.readsLocalCoords(); | |
173 fBatch.fCoverageIgnored = !overrides.readsCoverage(); | |
174 } | 146 } |
175 | 147 |
176 NonAAStrokeRectBatch() : INHERITED(ClassID()) {} | |
177 | |
178 GrColor color() const { return fBatch.fColor; } | |
179 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
180 bool colorIgnored() const { return fBatch.fColorIgnored; } | |
181 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
182 bool hairline() const { return fBatch.fHairline; } | |
183 bool coverageIgnored() const { return fBatch.fCoverageIgnored; } | |
184 | |
185 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { | 148 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override { |
186 // if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *t->pi peline(), | |
187 // t->bounds(), caps)) { | |
188 // return false; | |
189 // } | |
190 // GrStrokeRectBatch* that = t->cast<StrokeRectBatch>(); | |
191 | |
192 // NonAA stroke rects cannot batch right now | 149 // NonAA stroke rects cannot batch right now |
193 // TODO make these batchable | 150 // TODO make these batchable |
194 return false; | 151 return false; |
195 } | 152 } |
196 | 153 |
197 struct BatchTracker { | 154 GrColor fColor; |
198 GrColor fColor; | 155 SkMatrix fViewMatrix; |
199 bool fUsesLocalCoords; | 156 SkRect fRect; |
200 bool fColorIgnored; | 157 SkScalar fStrokeWidth; |
201 bool fCoverageIgnored; | 158 |
202 bool fHairline; | 159 GrXPOverridesForBatch fOverrides; |
203 }; | |
204 | 160 |
205 const static int kVertsPerHairlineRect = 5; | 161 const static int kVertsPerHairlineRect = 5; |
206 const static int kVertsPerStrokeRect = 10; | 162 const static int kVertsPerStrokeRect = 10; |
207 | 163 |
208 BatchTracker fBatch; | |
209 SkSTArray<1, Geometry, true> fGeoData; | |
210 | 164 |
211 typedef GrVertexBatch INHERITED; | 165 typedef GrVertexBatch INHERITED; |
212 }; | 166 }; |
213 | 167 |
214 // Allow all hairlines and all miters, so long as the miter limit doesn't produc e beveled corners. | |
215 inline static bool allowed_stroke(const SkStrokeRec& stroke) { | |
216 SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style || | |
217 stroke.getStyle() == SkStrokeRec::kHairline_Style); | |
218 return !stroke.getWidth() || | |
219 (stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_ ScalarSqrt2); | |
220 } | |
221 | |
222 namespace GrNonAAStrokeRectBatch { | 168 namespace GrNonAAStrokeRectBatch { |
223 | 169 |
224 GrDrawBatch* Create(GrColor color, | 170 GrDrawBatch* Create(GrColor color, |
225 const SkMatrix& viewMatrix, | 171 const SkMatrix& viewMatrix, |
226 const SkRect& rect, | 172 const SkRect& rect, |
227 const SkStrokeRec& stroke, | 173 const SkStrokeRec& stroke, |
228 bool snapToPixelCenters) { | 174 bool snapToPixelCenters) { |
229 if (!allowed_stroke(stroke)) { | 175 return NonAAStrokeRectBatch::Create(color, viewMatrix, rect, stroke, snapToP ixelCenters); |
230 return nullptr; | |
231 } | |
232 NonAAStrokeRectBatch* batch = NonAAStrokeRectBatch::Create(); | |
233 batch->append(color, viewMatrix, rect, stroke.getWidth()); | |
234 batch->init(snapToPixelCenters); | |
235 return batch; | |
236 } | 176 } |
237 | 177 |
238 }; | 178 } |
239 | 179 |
240 #ifdef GR_TEST_UTILS | 180 #ifdef GR_TEST_UTILS |
241 | 181 |
242 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { | 182 DRAW_BATCH_TEST_DEFINE(NonAAStrokeRectBatch) { |
243 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 183 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
244 GrColor color = GrRandomColor(random); | 184 GrColor color = GrRandomColor(random); |
245 SkRect rect = GrTest::TestRect(random); | 185 SkRect rect = GrTest::TestRect(random); |
246 SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f; | 186 SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f; |
247 SkPaint paint; | 187 SkPaint paint; |
248 paint.setStrokeWidth(strokeWidth); | 188 paint.setStrokeWidth(strokeWidth); |
249 paint.setStyle(SkPaint::kStroke_Style); | 189 paint.setStyle(SkPaint::kStroke_Style); |
250 paint.setStrokeJoin(SkPaint::kMiter_Join); | 190 paint.setStrokeJoin(SkPaint::kMiter_Join); |
251 SkStrokeRec strokeRec(paint); | 191 SkStrokeRec strokeRec(paint); |
252 return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, ra ndom->nextBool()); | 192 return GrNonAAStrokeRectBatch::Create(color, viewMatrix, rect, strokeRec, ra ndom->nextBool()); |
253 } | 193 } |
254 | 194 |
255 #endif | 195 #endif |
OLD | NEW |