blob: 4472b0125b74ea48fe9d968fa6b0d83eed876a3b [file] [log] [blame]
joshualitt9ff64252015-08-10 09:03:51 -07001/*
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 "GrAAStrokeRectBatch.h"
9
bsalomon75398562015-08-17 12:55:38 -070010#include "GrBatchFlushState.h"
joshualitt9ff64252015-08-10 09:03:51 -070011#include "GrDefaultGeoProcFactory.h"
12#include "GrResourceKey.h"
13#include "GrResourceProvider.h"
14
15GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
16GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
17
18static void set_inset_fan(SkPoint* pts, size_t stride,
19 const SkRect& r, SkScalar dx, SkScalar dy) {
20 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
21 r.fRight - dx, r.fBottom - dy, stride);
22}
23
24static const GrGeometryProcessor* create_stroke_rect_gp(bool tweakAlphaForCoverage,
25 const SkMatrix& viewMatrix,
26 bool usesLocalCoords,
27 bool coverageIgnored) {
28 using namespace GrDefaultGeoProcFactory;
29
30 Color color(Color::kAttribute_Type);
31 Coverage::Type coverageType;
32 // TODO remove coverage if coverage is ignored
33 /*if (coverageIgnored) {
34 coverageType = Coverage::kNone_Type;
35 } else*/ if (tweakAlphaForCoverage) {
36 coverageType = Coverage::kSolid_Type;
37 } else {
38 coverageType = Coverage::kAttribute_Type;
39 }
40 Coverage coverage(coverageType);
41 LocalCoords localCoords(usesLocalCoords ? LocalCoords::kUsePosition_Type :
42 LocalCoords::kUnused_Type);
43 return CreateForDeviceSpace(color, coverage, localCoords, viewMatrix);
44}
45
joshualitt3566d442015-09-18 07:12:55 -070046class AAStrokeRectBatch : public GrVertexBatch {
47public:
48 DEFINE_BATCH_CLASS_ID
49
50 // TODO support AA rotated stroke rects by copying around view matrices
51 struct Geometry {
52 SkRect fDevOutside;
53 SkRect fDevOutsideAssist;
54 SkRect fDevInside;
55 GrColor fColor;
56 bool fMiterStroke;
57 };
58
59 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, const SkRect& devOutside,
60 const SkRect& devOutsideAssist, const SkRect& devInside,
61 bool miterStroke) {
62 return new AAStrokeRectBatch(color, viewMatrix, devOutside, devOutsideAssist, devInside,
63 miterStroke);
64 }
65
66 const char* name() const override { return "AAStrokeRect"; }
67
68 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
69 // When this is called on a batch, there is only one geometry bundle
70 out->setKnownFourComponents(fGeoData[0].fColor);
71 }
72
73 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
74 out->setUnknownSingleComponent();
75 }
76
77 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
78
79private:
80 void onPrepareDraws(Target*) override;
81 void initBatchTracker(const GrPipelineOptimizations&) override;
82
83 AAStrokeRectBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& devOutside,
84 const SkRect& devOutsideAssist, const SkRect& devInside, bool miterStroke)
85 : INHERITED(ClassID()) {
86 fBatch.fViewMatrix = viewMatrix;
87 Geometry& geometry = fGeoData.push_back();
88 geometry.fColor = color;
89 geometry.fDevOutside = devOutside;
90 geometry.fDevOutsideAssist = devOutsideAssist;
91 geometry.fDevInside = devInside;
92 geometry.fMiterStroke = miterStroke;
93
94 // If we have miterstroke then we inset devOutside and outset devOutsideAssist, so we need
95 // the join for proper bounds
96 fBounds = geometry.fDevOutside;
97 fBounds.join(geometry.fDevOutsideAssist);
98 }
99
100
101 static const int kMiterIndexCnt = 3 * 24;
102 static const int kMiterVertexCnt = 16;
103 static const int kNumMiterRectsInIndexBuffer = 256;
104
105 static const int kBevelIndexCnt = 48 + 36 + 24;
106 static const int kBevelVertexCnt = 24;
107 static const int kNumBevelRectsInIndexBuffer = 256;
108
109 static const GrIndexBuffer* GetIndexBuffer(GrResourceProvider* resourceProvider,
110 bool miterStroke);
111
112 GrColor color() const { return fBatch.fColor; }
113 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
114 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
115 bool colorIgnored() const { return fBatch.fColorIgnored; }
116 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
117 bool miterStroke() const { return fBatch.fMiterStroke; }
118 bool coverageIgnored() const { return fBatch.fCoverageIgnored; }
119
120 bool onCombineIfPossible(GrBatch* t, const GrCaps&) override;
121
122 void generateAAStrokeRectGeometry(void* vertices,
123 size_t offset,
124 size_t vertexStride,
125 int outerVertexNum,
126 int innerVertexNum,
127 GrColor color,
128 const SkRect& devOutside,
129 const SkRect& devOutsideAssist,
130 const SkRect& devInside,
131 bool miterStroke,
132 bool tweakAlphaForCoverage) const;
133
134 struct BatchTracker {
135 SkMatrix fViewMatrix;
136 GrColor fColor;
137 bool fUsesLocalCoords;
138 bool fColorIgnored;
139 bool fCoverageIgnored;
140 bool fMiterStroke;
141 bool fCanTweakAlphaForCoverage;
142 };
143
144 BatchTracker fBatch;
145 SkSTArray<1, Geometry, true> fGeoData;
146
147 typedef GrVertexBatch INHERITED;
148};
149
150void AAStrokeRectBatch::initBatchTracker(const GrPipelineOptimizations& opt) {
joshualitt9ff64252015-08-10 09:03:51 -0700151 // Handle any color overrides
bsalomon91d844d2015-08-10 10:47:29 -0700152 if (!opt.readsColor()) {
joshualitt9ff64252015-08-10 09:03:51 -0700153 fGeoData[0].fColor = GrColor_ILLEGAL;
154 }
bsalomon91d844d2015-08-10 10:47:29 -0700155 opt.getOverrideColorIfSet(&fGeoData[0].fColor);
joshualitt9ff64252015-08-10 09:03:51 -0700156
157 // setup batch properties
bsalomon91d844d2015-08-10 10:47:29 -0700158 fBatch.fColorIgnored = !opt.readsColor();
joshualitt9ff64252015-08-10 09:03:51 -0700159 fBatch.fColor = fGeoData[0].fColor;
bsalomon91d844d2015-08-10 10:47:29 -0700160 fBatch.fUsesLocalCoords = opt.readsLocalCoords();
161 fBatch.fCoverageIgnored = !opt.readsCoverage();
joshualitt9ff64252015-08-10 09:03:51 -0700162 fBatch.fMiterStroke = fGeoData[0].fMiterStroke;
bsalomon91d844d2015-08-10 10:47:29 -0700163 fBatch.fCanTweakAlphaForCoverage = opt.canTweakAlphaForCoverage();
joshualitt9ff64252015-08-10 09:03:51 -0700164}
165
joshualitt3566d442015-09-18 07:12:55 -0700166void AAStrokeRectBatch::onPrepareDraws(Target* target) {
joshualitt9ff64252015-08-10 09:03:51 -0700167 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
168
169 SkAutoTUnref<const GrGeometryProcessor> gp(create_stroke_rect_gp(canTweakAlphaForCoverage,
170 this->viewMatrix(),
171 this->usesLocalCoords(),
172 this->coverageIgnored()));
173 if (!gp) {
174 SkDebugf("Couldn't create GrGeometryProcessor\n");
175 return;
176 }
177
bsalomon75398562015-08-17 12:55:38 -0700178 target->initDraw(gp, this->pipeline());
joshualitt9ff64252015-08-10 09:03:51 -0700179
180 size_t vertexStride = gp->getVertexStride();
181
182 SkASSERT(canTweakAlphaForCoverage ?
183 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
184 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
185 int innerVertexNum = 4;
186 int outerVertexNum = this->miterStroke() ? 4 : 8;
187 int verticesPerInstance = (outerVertexNum + innerVertexNum) * 2;
188 int indicesPerInstance = this->miterStroke() ? kMiterIndexCnt : kBevelIndexCnt;
189 int instanceCount = fGeoData.count();
190
191 const SkAutoTUnref<const GrIndexBuffer> indexBuffer(
bsalomon75398562015-08-17 12:55:38 -0700192 GetIndexBuffer(target->resourceProvider(), this->miterStroke()));
joshualitt9ff64252015-08-10 09:03:51 -0700193 InstancedHelper helper;
bsalomon75398562015-08-17 12:55:38 -0700194 void* vertices = helper.init(target, kTriangles_GrPrimitiveType, vertexStride,
joshualitt9ff64252015-08-10 09:03:51 -0700195 indexBuffer, verticesPerInstance, indicesPerInstance,
196 instanceCount);
197 if (!vertices || !indexBuffer) {
198 SkDebugf("Could not allocate vertices\n");
199 return;
200 }
201
202 for (int i = 0; i < instanceCount; i++) {
203 const Geometry& args = fGeoData[i];
204 this->generateAAStrokeRectGeometry(vertices,
205 i * verticesPerInstance * vertexStride,
206 vertexStride,
207 outerVertexNum,
208 innerVertexNum,
209 args.fColor,
210 args.fDevOutside,
211 args.fDevOutsideAssist,
212 args.fDevInside,
213 args.fMiterStroke,
214 canTweakAlphaForCoverage);
215 }
bsalomon75398562015-08-17 12:55:38 -0700216 helper.recordDraw(target);
joshualitt9ff64252015-08-10 09:03:51 -0700217}
218
joshualitt3566d442015-09-18 07:12:55 -0700219const GrIndexBuffer* AAStrokeRectBatch::GetIndexBuffer(GrResourceProvider* resourceProvider,
220 bool miterStroke) {
joshualitt9ff64252015-08-10 09:03:51 -0700221
222 if (miterStroke) {
223 static const uint16_t gMiterIndices[] = {
224 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
225 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
226 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
227 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
228
229 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
230 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
231 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
232 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
233
234 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
235 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
236 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
237 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
238 };
239 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gMiterIndices) == kMiterIndexCnt);
240 GR_DEFINE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
241 return resourceProvider->findOrCreateInstancedIndexBuffer(gMiterIndices,
242 kMiterIndexCnt, kNumMiterRectsInIndexBuffer, kMiterVertexCnt,
243 gMiterIndexBufferKey);
244 } else {
245 /**
246 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
247 * from the first index. The index layout:
248 * outer AA line: 0~3, 4~7
249 * outer edge: 8~11, 12~15
250 * inner edge: 16~19
251 * inner AA line: 20~23
252 * Following comes a bevel-stroke rect and its indices:
253 *
254 * 4 7
255 * *********************************
256 * * ______________________________ *
257 * * / 12 15 \ *
258 * * / \ *
259 * 0 * |8 16_____________________19 11 | * 3
260 * * | | | | *
261 * * | | **************** | | *
262 * * | | * 20 23 * | | *
263 * * | | * * | | *
264 * * | | * 21 22 * | | *
265 * * | | **************** | | *
266 * * | |____________________| | *
267 * 1 * |9 17 18 10| * 2
268 * * \ / *
269 * * \13 __________________________14/ *
270 * * *
271 * **********************************
272 * 5 6
273 */
274 static const uint16_t gBevelIndices[] = {
275 // Draw outer AA, from outer AA line to outer edge, shift is 0.
276 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
277 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
278 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
279 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
280 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
281 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
282 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
283 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
284
285 // Draw the stroke, from outer edge to inner edge, shift is 8.
286 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
287 1 + 8, 5 + 8, 9 + 8,
288 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
289 6 + 8, 2 + 8, 10 + 8,
290 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
291 3 + 8, 7 + 8, 11 + 8,
292 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
293 4 + 8, 0 + 8, 8 + 8,
294
295 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
296 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
297 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
298 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
299 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
300 };
301 GR_STATIC_ASSERT(SK_ARRAY_COUNT(gBevelIndices) == kBevelIndexCnt);
302
303 GR_DEFINE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
304 return resourceProvider->findOrCreateInstancedIndexBuffer(gBevelIndices,
305 kBevelIndexCnt, kNumBevelRectsInIndexBuffer, kBevelVertexCnt,
306 gBevelIndexBufferKey);
307 }
308}
309
joshualitt3566d442015-09-18 07:12:55 -0700310bool AAStrokeRectBatch::onCombineIfPossible(GrBatch* t, const GrCaps& caps) {
311 AAStrokeRectBatch* that = t->cast<AAStrokeRectBatch>();
bsalomonabd30f52015-08-13 13:34:48 -0700312
313 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(),
314 that->bounds(), caps)) {
joshualitt9ff64252015-08-10 09:03:51 -0700315 return false;
316 }
317
joshualitt9ff64252015-08-10 09:03:51 -0700318 // TODO batch across miterstroke changes
319 if (this->miterStroke() != that->miterStroke()) {
320 return false;
321 }
322
323 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
324 // local coords then we won't be able to batch. We could actually upload the viewmatrix
325 // using vertex attributes in these cases, but haven't investigated that
326 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
327 return false;
328 }
329
330 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
331 // not tweaking
332 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
333 fBatch.fCanTweakAlphaForCoverage = false;
334 }
335
336 if (this->color() != that->color()) {
337 fBatch.fColor = GrColor_ILLEGAL;
338 }
339 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
340 this->joinBounds(that->bounds());
341 return true;
342}
343
joshualitt3566d442015-09-18 07:12:55 -0700344void AAStrokeRectBatch::generateAAStrokeRectGeometry(void* vertices,
345 size_t offset,
346 size_t vertexStride,
347 int outerVertexNum,
348 int innerVertexNum,
349 GrColor color,
350 const SkRect& devOutside,
351 const SkRect& devOutsideAssist,
352 const SkRect& devInside,
353 bool miterStroke,
354 bool tweakAlphaForCoverage) const {
joshualitt9ff64252015-08-10 09:03:51 -0700355 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
356
357 // We create vertices for four nested rectangles. There are two ramps from 0 to full
358 // coverage, one on the exterior of the stroke and the other on the interior.
359 // The following pointers refer to the four rects, from outermost to innermost.
360 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
361 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vertexStride);
362 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vertexStride);
363 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts +
364 (2 * outerVertexNum + innerVertexNum) *
365 vertexStride);
366
367#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
368 // TODO: this only really works if the X & Y margins are the same all around
369 // the rect (or if they are all >= 1.0).
370 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
371 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
372 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
373 if (miterStroke) {
374 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
375 } else {
376 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom -
377 devInside.fBottom);
378 }
379 SkASSERT(inset >= 0);
380#else
381 SkScalar inset = SK_ScalarHalf;
382#endif
383
384 if (miterStroke) {
385 // outermost
386 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
387 // inner two
388 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
389 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
390 // innermost
391 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
392 } else {
393 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
394 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts +
395 (outerVertexNum + 4) *
396 vertexStride);
397 // outermost
398 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
399 set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf,
400 -SK_ScalarHalf);
401 // outer one of the inner two
402 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
403 set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset);
404 // inner one of the inner two
405 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
406 // innermost
407 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
408 }
409
410 // Make verts point to vertex color and then set all the color and coverage vertex attrs
411 // values. The outermost rect has 0 coverage
412 verts += sizeof(SkPoint);
413 for (int i = 0; i < outerVertexNum; ++i) {
414 if (tweakAlphaForCoverage) {
415 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
416 } else {
417 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
418 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
419 }
420 }
421
422 // scale is the coverage for the the inner two rects.
423 int scale;
424 if (inset < SK_ScalarHalf) {
425 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
426 SkASSERT(scale >= 0 && scale <= 255);
427 } else {
428 scale = 0xff;
429 }
430
431 float innerCoverage = GrNormalizeByteToFloat(scale);
432 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
433
434 verts += outerVertexNum * vertexStride;
435 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
436 if (tweakAlphaForCoverage) {
437 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
438 } else {
439 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
440 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
441 innerCoverage;
442 }
443 }
444
445 // The innermost rect has 0 coverage
446 verts += (outerVertexNum + innerVertexNum) * vertexStride;
447 for (int i = 0; i < innerVertexNum; ++i) {
448 if (tweakAlphaForCoverage) {
449 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
450 } else {
451 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
452 *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
453 }
454 }
455}
456
joshualitt3566d442015-09-18 07:12:55 -0700457namespace GrAAStrokeRectBatch {
458
459GrDrawBatch* Create(GrColor color,
460 const SkMatrix& viewMatrix,
461 const SkRect& devOutside,
462 const SkRect& devOutsideAssist,
463 const SkRect& devInside,
464 bool miterStroke) {
465 return AAStrokeRectBatch::Create(color, viewMatrix, devOutside, devOutsideAssist, devInside,
466 miterStroke);
467}
468
469};
470
joshualitt9ff64252015-08-10 09:03:51 -0700471///////////////////////////////////////////////////////////////////////////////////////////////////
472
473#ifdef GR_TEST_UTILS
474
475#include "GrBatchTest.h"
476
bsalomonabd30f52015-08-13 13:34:48 -0700477DRAW_BATCH_TEST_DEFINE(AAStrokeRectBatch) {
joshualitt9ff64252015-08-10 09:03:51 -0700478 bool miterStroke = random->nextBool();
479
480 // Create mock stroke rect
481 SkRect outside = GrTest::TestRect(random);
482 SkScalar minDim = SkMinScalar(outside.width(), outside.height());
483 SkScalar strokeWidth = minDim * 0.1f;
484 SkRect outsideAssist = outside;
485 outsideAssist.outset(strokeWidth, strokeWidth);
486 SkRect inside = outside;
487 inside.inset(strokeWidth, strokeWidth);
488
joshualitt3566d442015-09-18 07:12:55 -0700489 GrColor color = GrRandomColor(random);
joshualitt9ff64252015-08-10 09:03:51 -0700490
joshualitt3566d442015-09-18 07:12:55 -0700491 return GrAAStrokeRectBatch::Create(color, GrTest::TestMatrix(random), outside, outsideAssist,
492 inside, miterStroke);
joshualitt9ff64252015-08-10 09:03:51 -0700493}
494
495#endif