blob: 2cc8f95addc2415ca00094becb82fd2d389ef2e1 [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +00001/*
2 * Copyright 2012 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 "GrAARectRenderer.h"
joshualitt4d8da812015-01-28 12:53:54 -08009#include "GrBatch.h"
10#include "GrBatchTarget.h"
11#include "GrBufferAllocPool.h"
joshualitt5478d422014-11-14 16:00:38 -080012#include "GrDefaultGeoProcFactory.h"
13#include "GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000014#include "GrGpu.h"
egdaniel605dd0f2014-11-12 08:35:25 -080015#include "GrInvariantOutput.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000016#include "SkColorPriv.h"
joshualitt5478d422014-11-14 16:00:38 -080017#include "gl/GrGLProcessor.h"
18#include "gl/GrGLGeometryProcessor.h"
19#include "gl/builders/GrGLProgramBuilder.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000020
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000021///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000022
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000023static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000024 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000025 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
26 r.fRight - dx, r.fBottom - dy, stride);
27}
28
robertphillips@google.com6d067302012-12-18 21:47:47 +000029static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000030 0, 1, 5, 5, 4, 0,
31 1, 2, 6, 6, 5, 1,
32 2, 3, 7, 7, 6, 2,
33 3, 0, 4, 4, 7, 3,
34 4, 5, 6, 6, 7, 4,
35};
36
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000037static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000038static const int kVertsPerAAFillRect = 8;
39static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000040
joshualitt4d8da812015-01-28 12:53:54 -080041static const GrGeometryProcessor* create_fill_rect_gp(bool tweakAlphaForCoverage,
42 const SkMatrix& localMatrix) {
43 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
44 const GrGeometryProcessor* gp;
45 if (tweakAlphaForCoverage) {
46 gp = GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE, SkMatrix::I(), localMatrix,
47 false, 0xff);
48 } else {
49 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
50 gp = GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE, SkMatrix::I(), localMatrix,
51 false, 0xff);
52 }
53 return gp;
54}
55
56class AAFillRectBatch : public GrBatch {
57public:
58 struct Geometry {
59 GrColor fColor;
60 SkMatrix fViewMatrix;
61 SkRect fRect;
62 SkRect fDevRect;
63 };
64
65 static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
66 return SkNEW_ARGS(AAFillRectBatch, (geometry, indexBuffer));
67 }
68
69 const char* name() const SK_OVERRIDE { return "AAFillRectBatch"; }
70
71 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
72 // When this is called on a batch, there is only one geometry bundle
joshualittdb0f9512015-02-13 12:50:09 -080073 out->setKnownFourComponents(fGeoData[0].fColor);
joshualitt4d8da812015-01-28 12:53:54 -080074 }
75
76 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
joshualittdb0f9512015-02-13 12:50:09 -080077 out->setUnknownSingleComponent();
joshualitt4d8da812015-01-28 12:53:54 -080078 }
79
80 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
81 // Handle any color overrides
82 if (init.fColorIgnored) {
83 fGeoData[0].fColor = GrColor_ILLEGAL;
84 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
85 fGeoData[0].fColor = init.fOverrideColor;
86 }
87
88 // setup batch properties
89 fBatch.fColorIgnored = init.fColorIgnored;
90 fBatch.fColor = fGeoData[0].fColor;
91 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
92 fBatch.fCoverageIgnored = init.fCoverageIgnored;
joshualittdb0f9512015-02-13 12:50:09 -080093 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
joshualitt4d8da812015-01-28 12:53:54 -080094 }
95
96 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
97 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
98
99 SkMatrix localMatrix;
joshualitt4283f132015-02-13 14:25:10 -0800100 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
joshualitt4d8da812015-01-28 12:53:54 -0800101 SkDebugf("Cannot invert\n");
102 return;
103 }
104
joshualitt4283f132015-02-13 14:25:10 -0800105 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
106 localMatrix));
joshualitt4d8da812015-01-28 12:53:54 -0800107
108 batchTarget->initDraw(gp, pipeline);
joshualitt4d8da812015-01-28 12:53:54 -0800109
110 // TODO this is hacky, but the only way we have to initialize the GP is to use the
111 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
112 // everywhere we can remove this nastiness
113 GrPipelineInfo init;
114 init.fColorIgnored = fBatch.fColorIgnored;
115 init.fOverrideColor = GrColor_ILLEGAL;
116 init.fCoverageIgnored = fBatch.fCoverageIgnored;
117 init.fUsesLocalCoords = this->usesLocalCoords();
118 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
119
120 size_t vertexStride = gp->getVertexStride();
121
122 SkASSERT(canTweakAlphaForCoverage ?
123 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
124 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
125
126 int instanceCount = fGeoData.count();
127 int vertexCount = kVertsPerAAFillRect * instanceCount;
128
129 const GrVertexBuffer* vertexBuffer;
130 int firstVertex;
131
joshualitt4283f132015-02-13 14:25:10 -0800132 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
joshualitt4d8da812015-01-28 12:53:54 -0800133 vertexCount,
134 &vertexBuffer,
135 &firstVertex);
136
137 for (int i = 0; i < instanceCount; i++) {
138 const Geometry& args = fGeoData[i];
139 this->generateAAFillRectGeometry(vertices,
joshualitt4283f132015-02-13 14:25:10 -0800140 i * kVertsPerAAFillRect * vertexStride,
141 vertexStride,
142 args.fColor,
143 args.fViewMatrix,
144 args.fRect,
145 args.fDevRect,
146 canTweakAlphaForCoverage);
joshualitt4d8da812015-01-28 12:53:54 -0800147 }
148
149 GrDrawTarget::DrawInfo drawInfo;
150 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
151 drawInfo.setStartVertex(0);
152 drawInfo.setStartIndex(0);
153 drawInfo.setVerticesPerInstance(kVertsPerAAFillRect);
154 drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect);
155 drawInfo.adjustStartVertex(firstVertex);
156 drawInfo.setVertexBuffer(vertexBuffer);
157 drawInfo.setIndexBuffer(fIndexBuffer);
158
159 int maxInstancesPerDraw = kNumAAFillRectsInIndexBuffer;
160
161 while (instanceCount) {
162 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
163 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
164 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
165
166 batchTarget->draw(drawInfo);
167
168 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
169 instanceCount -= drawInfo.instanceCount();
170 }
171 }
172
173 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
174
175private:
176 AAFillRectBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
177 : fIndexBuffer(indexBuffer) {
178 this->initClassID<AAFillRectBatch>();
179 fGeoData.push_back(geometry);
180 }
181
182 GrColor color() const { return fBatch.fColor; }
183 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
joshualittdb0f9512015-02-13 12:50:09 -0800184 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
joshualitt4d8da812015-01-28 12:53:54 -0800185 bool colorIgnored() const { return fBatch.fColorIgnored; }
186 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
187
188 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
189 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
joshualitt84b13df2015-02-12 15:03:49 -0800190
191 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
joshualitt4d8da812015-01-28 12:53:54 -0800192 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
193 // local coords then we won't be able to batch. We could actually upload the viewmatrix
194 // using vertex attributes in these cases, but haven't investigated that
195 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
196 return false;
197 }
198
199 if (this->color() != that->color()) {
200 fBatch.fColor = GrColor_ILLEGAL;
201 }
joshualittdb0f9512015-02-13 12:50:09 -0800202
203 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
204 // not tweaking
205 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
206 fBatch.fCanTweakAlphaForCoverage = false;
207 }
208
joshualitt4d8da812015-01-28 12:53:54 -0800209 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
210 return true;
211 }
212
213 void generateAAFillRectGeometry(void* vertices,
bsalomon81aca542015-01-29 07:13:20 -0800214 size_t offset,
215 size_t vertexStride,
joshualitt4d8da812015-01-28 12:53:54 -0800216 GrColor color,
217 const SkMatrix& viewMatrix,
218 const SkRect& rect,
219 const SkRect& devRect,
220 bool tweakAlphaForCoverage) const {
221 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
222
223 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
224 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
225
226 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
227 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
228
229 if (viewMatrix.rectStaysRect()) {
230 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
231 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
232 } else {
233 // compute transformed (1, 0) and (0, 1) vectors
234 SkVector vec[2] = {
235 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
236 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
237 };
238
239 vec[0].normalize();
240 vec[0].scale(SK_ScalarHalf);
241 vec[1].normalize();
242 vec[1].scale(SK_ScalarHalf);
243
244 // create the rotated rect
245 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
246 rect.fRight, rect.fBottom, vertexStride);
247 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
248
249 // Now create the inset points and then outset the original
250 // rotated points
251
252 // TL
253 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
254 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
255 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
256 // BL
257 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
258 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
259 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
260 // BR
261 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
262 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
263 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
264 // TR
265 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
266 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
267 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
268 }
269
270 // Make verts point to vertex color and then set all the color and coverage vertex attrs
271 // values.
272 verts += sizeof(SkPoint);
273 for (int i = 0; i < 4; ++i) {
274 if (tweakAlphaForCoverage) {
275 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
276 } else {
277 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
278 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
279 }
280 }
281
282 int scale;
283 if (inset < SK_ScalarHalf) {
284 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
285 SkASSERT(scale >= 0 && scale <= 255);
286 } else {
287 scale = 0xff;
288 }
289
290 verts += 4 * vertexStride;
291
292 float innerCoverage = GrNormalizeByteToFloat(scale);
293 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
294
295 for (int i = 0; i < 4; ++i) {
296 if (tweakAlphaForCoverage) {
297 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
298 } else {
299 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
300 *reinterpret_cast<float*>(verts + i * vertexStride +
301 sizeof(GrColor)) = innerCoverage;
302 }
303 }
304 }
305
306 struct BatchTracker {
307 GrColor fColor;
308 bool fUsesLocalCoords;
309 bool fColorIgnored;
310 bool fCoverageIgnored;
joshualittdb0f9512015-02-13 12:50:09 -0800311 bool fCanTweakAlphaForCoverage;
joshualitt4d8da812015-01-28 12:53:54 -0800312 };
313
joshualitt4d8da812015-01-28 12:53:54 -0800314 BatchTracker fBatch;
315 const GrIndexBuffer* fIndexBuffer;
316 SkSTArray<1, Geometry, true> fGeoData;
317};
318
319namespace {
320// Should the coverage be multiplied into the color attrib or use a separate attrib.
321enum CoverageAttribType {
322 kUseColor_CoverageAttribType,
323 kUseCoverage_CoverageAttribType,
324};
325}
326
327void GrAARectRenderer::reset() {
328 SkSafeSetNull(fAAFillRectIndexBuffer);
329 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
330 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
331}
332
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000333static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000334 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
335 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
336 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
337 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
338
339 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
340 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
341 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
342 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
343
344 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
345 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
346 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
347 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
348};
349
joshualitt5ead6da2014-10-22 16:00:29 -0700350static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
351static const int kVertsPerMiterStrokeRect = 16;
352static const int kNumMiterStrokeRectsInIndexBuffer = 256;
353
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000354/**
355 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
356 * from the first index. The index layout:
357 * outer AA line: 0~3, 4~7
358 * outer edge: 8~11, 12~15
359 * inner edge: 16~19
360 * inner AA line: 20~23
361 * Following comes a bevel-stroke rect and its indices:
362 *
363 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000364 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000365 * * ______________________________ *
366 * * / 12 15 \ *
367 * * / \ *
368 * 0 * |8 16_____________________19 11 | * 3
369 * * | | | | *
370 * * | | **************** | | *
371 * * | | * 20 23 * | | *
372 * * | | * * | | *
373 * * | | * 21 22 * | | *
374 * * | | **************** | | *
375 * * | |____________________| | *
376 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000377 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000378 * * \13 __________________________14/ *
379 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000380 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000381 * 5 6
382 */
383static const uint16_t gBevelStrokeAARectIdx[] = {
384 // Draw outer AA, from outer AA line to outer edge, shift is 0.
385 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
386 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
387 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
388 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
389 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
390 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
391 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
392 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
393
394 // Draw the stroke, from outer edge to inner edge, shift is 8.
395 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
396 1 + 8, 5 + 8, 9 + 8,
397 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
398 6 + 8, 2 + 8, 10 + 8,
399 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
400 3 + 8, 7 + 8, 11 + 8,
401 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
402 4 + 8, 0 + 8, 8 + 8,
403
404 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
405 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
406 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
407 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
408 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
409};
410
joshualitt5ead6da2014-10-22 16:00:29 -0700411static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
412static const int kVertsPerBevelStrokeRect = 24;
413static const int kNumBevelStrokeRectsInIndexBuffer = 256;
414
joshualittb44293e2014-10-28 08:12:18 -0700415static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000416 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
417 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000418}
419
joshualittb44293e2014-10-28 08:12:18 -0700420GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000421 if (miterStroke) {
422 if (NULL == fAAMiterStrokeRectIndexBuffer) {
423 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700424 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
425 kIndicesPerMiterStrokeRect,
426 kNumMiterStrokeRectsInIndexBuffer,
427 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000428 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000429 return fAAMiterStrokeRectIndexBuffer;
430 } else {
431 if (NULL == fAABevelStrokeRectIndexBuffer) {
432 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700433 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
434 kIndicesPerBevelStrokeRect,
435 kNumBevelStrokeRectsInIndexBuffer,
436 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000437 }
438 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000439 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000440}
441
joshualittb44293e2014-10-28 08:12:18 -0700442void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800443 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800444 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800445 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000446 const SkRect& rect,
bsalomon9c0822a2014-08-11 11:07:48 -0700447 const SkRect& devRect) {
joshualitt5ead6da2014-10-22 16:00:29 -0700448 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700449 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
450 kIndicesPerAAFillRect,
451 kNumAAFillRectsInIndexBuffer,
452 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700453 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000454
joshualitt4d8da812015-01-28 12:53:54 -0800455 AAFillRectBatch::Geometry geometry;
456 geometry.fRect = rect;
457 geometry.fViewMatrix = viewMatrix;
458 geometry.fDevRect = devRect;
459 geometry.fColor = color;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000460
joshualitt4d8da812015-01-28 12:53:54 -0800461 SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
462 target->drawBatch(pipelineBuilder, batch, &devRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463}
464
joshualittb44293e2014-10-28 08:12:18 -0700465void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800466 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800467 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800468 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000469 const SkRect& rect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000470 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700471 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000472 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700473 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000474 if (width > 0) {
475 devStrokeSize.set(width, width);
joshualitt8059eb92014-12-29 15:10:07 -0800476 viewMatrix.mapVectors(&devStrokeSize, 1);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000477 devStrokeSize.setAbs(devStrokeSize);
478 } else {
479 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
480 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000481
robertphillips@google.com18136d12013-05-10 11:05:58 +0000482 const SkScalar dx = devStrokeSize.fX;
483 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000484 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
485 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000486
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000487 // Temporarily #if'ed out. We don't want to pass in the devRect but
488 // right now it is computed in GrContext::apply_aa_to_rect and we don't
489 // want to throw away the work
490#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000491 SkRect devRect;
492 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000493#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000494
bsalomon@google.com81712882012-11-01 17:12:34 +0000495 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000496 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000497 SkScalar w = devRect.width() - dx;
498 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000499 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000500 }
501
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000502 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000503 devOutside.outset(rx, ry);
504
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000505 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700506 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000507 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700508 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
509 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000510 miterStroke = false;
511 }
512
513 if (spare <= 0 && miterStroke) {
egdaniel8dd688b2015-01-22 10:16:09 -0800514 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800515 devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000516 return;
517 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000518
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000519 SkRect devInside(devRect);
520 devInside.inset(rx, ry);
521
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000522 SkRect devOutsideAssist(devRect);
523
524 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
525 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000526 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000527 if (!miterStroke) {
528 devOutside.inset(0, ry);
529 devOutsideAssist.outset(0, ry);
530 }
531
joshualitt4d8da812015-01-28 12:53:54 -0800532 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
533 devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000534}
535
joshualitt4283f132015-02-13 14:25:10 -0800536class AAStrokeRectBatch : public GrBatch {
537public:
538 // TODO support AA rotated stroke rects by copying around view matrices
539 struct Geometry {
540 GrColor fColor;
541 SkRect fDevOutside;
542 SkRect fDevOutsideAssist;
543 SkRect fDevInside;
544 bool fMiterStroke;
545 };
546
547 static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
548 const GrIndexBuffer* indexBuffer) {
549 return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix, indexBuffer));
joshualitt4d8da812015-01-28 12:53:54 -0800550 }
joshualitt4283f132015-02-13 14:25:10 -0800551
552 const char* name() const SK_OVERRIDE { return "AAStrokeRect"; }
553
554 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
555 // When this is called on a batch, there is only one geometry bundle
556 out->setKnownFourComponents(fGeoData[0].fColor);
557 }
558
559 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
560 out->setUnknownSingleComponent();
561 }
562
563 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
564 // Handle any color overrides
565 if (init.fColorIgnored) {
566 fGeoData[0].fColor = GrColor_ILLEGAL;
567 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
568 fGeoData[0].fColor = init.fOverrideColor;
569 }
570
571 // setup batch properties
572 fBatch.fColorIgnored = init.fColorIgnored;
573 fBatch.fColor = fGeoData[0].fColor;
574 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
575 fBatch.fCoverageIgnored = init.fCoverageIgnored;
576 fBatch.fMiterStroke = fGeoData[0].fMiterStroke;
577 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
578 }
579
580 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
581 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
582
583 // Local matrix is ignored if we don't have local coords. If we have localcoords we only
584 // batch with identical view matrices
585 SkMatrix localMatrix;
586 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
587 SkDebugf("Cannot invert\n");
588 return;
589 }
590
joshualitt332c7292015-02-23 08:44:31 -0800591 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
592 localMatrix));
joshualitt4283f132015-02-13 14:25:10 -0800593
594 batchTarget->initDraw(gp, pipeline);
595
596 // TODO this is hacky, but the only way we have to initialize the GP is to use the
597 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
598 // everywhere we can remove this nastiness
599 GrPipelineInfo init;
600 init.fColorIgnored = fBatch.fColorIgnored;
601 init.fOverrideColor = GrColor_ILLEGAL;
602 init.fCoverageIgnored = fBatch.fCoverageIgnored;
603 init.fUsesLocalCoords = this->usesLocalCoords();
604 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
605
606 size_t vertexStride = gp->getVertexStride();
607
608 SkASSERT(canTweakAlphaForCoverage ?
609 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
610 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
611
612 int innerVertexNum = 4;
613 int outerVertexNum = this->miterStroke() ? 4 : 8;
614 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
615
616 int instanceCount = fGeoData.count();
617 int vertexCount = totalVertexNum * instanceCount;
618
619 const GrVertexBuffer* vertexBuffer;
620 int firstVertex;
621
622 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
623 vertexCount,
624 &vertexBuffer,
625 &firstVertex);
626
627 for (int i = 0; i < instanceCount; i++) {
628 const Geometry& args = fGeoData[i];
629 this->generateAAStrokeRectGeometry(vertices,
630 i * totalVertexNum * vertexStride,
631 vertexStride,
632 outerVertexNum,
633 innerVertexNum,
634 args.fColor,
635 args.fDevOutside,
636 args.fDevOutsideAssist,
637 args.fDevInside,
638 args.fMiterStroke,
639 canTweakAlphaForCoverage);
640 }
641
642 GrDrawTarget::DrawInfo drawInfo;
643 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
644 drawInfo.setStartVertex(0);
645 drawInfo.setStartIndex(0);
646 drawInfo.setVerticesPerInstance(totalVertexNum);
647 drawInfo.setIndicesPerInstance(aa_stroke_rect_index_count(this->miterStroke()));
648 drawInfo.adjustStartVertex(firstVertex);
649 drawInfo.setVertexBuffer(vertexBuffer);
650 drawInfo.setIndexBuffer(fIndexBuffer);
651
652 int maxInstancesPerDraw = kNumBevelStrokeRectsInIndexBuffer;
653
654 while (instanceCount) {
655 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
656 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
657 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
658
659 batchTarget->draw(drawInfo);
660
661 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
662 instanceCount -= drawInfo.instanceCount();
663 }
664 }
665
666 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
667
668private:
669 AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix,
670 const GrIndexBuffer* indexBuffer)
671 : fIndexBuffer(indexBuffer) {
672 this->initClassID<AAStrokeRectBatch>();
673 fBatch.fViewMatrix = viewMatrix;
674 fGeoData.push_back(geometry);
675 }
676
677 GrColor color() const { return fBatch.fColor; }
678 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
679 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
680 bool colorIgnored() const { return fBatch.fColorIgnored; }
681 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
682 bool miterStroke() const { return fBatch.fMiterStroke; }
683
684 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
685 AAStrokeRectBatch* that = t->cast<AAStrokeRectBatch>();
686
687 // TODO batch across miterstroke changes
688 if (this->miterStroke() != that->miterStroke()) {
689 return false;
690 }
691
692 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
693 // local coords then we won't be able to batch. We could actually upload the viewmatrix
694 // using vertex attributes in these cases, but haven't investigated that
695 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
696 return false;
697 }
698
699 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
700 // not tweaking
701 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
702 fBatch.fCanTweakAlphaForCoverage = false;
703 }
704
705 if (this->color() != that->color()) {
706 fBatch.fColor = GrColor_ILLEGAL;
707 }
708 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
709 return true;
710 }
711
712 void generateAAStrokeRectGeometry(void* vertices,
713 size_t offset,
714 size_t vertexStride,
715 int outerVertexNum,
716 int innerVertexNum,
717 GrColor color,
718 const SkRect& devOutside,
719 const SkRect& devOutsideAssist,
720 const SkRect& devInside,
721 bool miterStroke,
722 bool tweakAlphaForCoverage) const {
723 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
724
725 // We create vertices for four nested rectangles. There are two ramps from 0 to full
726 // coverage, one on the exterior of the stroke and the other on the interior.
727 // The following pointers refer to the four rects, from outermost to innermost.
728 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
729 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vertexStride);
730 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vertexStride);
731 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts +
732 (2 * outerVertexNum + innerVertexNum) *
733 vertexStride);
734
735 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
736 // TODO: this only really works if the X & Y margins are the same all around
737 // the rect (or if they are all >= 1.0).
738 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
739 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
740 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
741 if (miterStroke) {
742 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
743 } else {
744 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom -
745 devInside.fBottom);
746 }
747 SkASSERT(inset >= 0);
748 #else
749 SkScalar inset = SK_ScalarHalf;
750 #endif
751
752 if (miterStroke) {
753 // outermost
754 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
755 // inner two
756 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
757 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
758 // innermost
759 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
760 } else {
761 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
762 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts +
763 (outerVertexNum + 4) *
764 vertexStride);
765 // outermost
766 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
767 set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf,
768 -SK_ScalarHalf);
769 // outer one of the inner two
770 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
771 set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset);
772 // inner one of the inner two
773 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
774 // innermost
775 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
776 }
777
778 // Make verts point to vertex color and then set all the color and coverage vertex attrs
779 // values. The outermost rect has 0 coverage
780 verts += sizeof(SkPoint);
781 for (int i = 0; i < outerVertexNum; ++i) {
782 if (tweakAlphaForCoverage) {
783 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
784 } else {
785 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
786 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
787 }
788 }
789
790 // scale is the coverage for the the inner two rects.
791 int scale;
792 if (inset < SK_ScalarHalf) {
793 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
794 SkASSERT(scale >= 0 && scale <= 255);
795 } else {
796 scale = 0xff;
797 }
798
799 float innerCoverage = GrNormalizeByteToFloat(scale);
800 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
801
802 verts += outerVertexNum * vertexStride;
803 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
804 if (tweakAlphaForCoverage) {
805 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
806 } else {
807 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
808 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
809 innerCoverage;
810 }
811 }
812
813 // The innermost rect has 0 coverage
814 verts += (outerVertexNum + innerVertexNum) * vertexStride;
815 for (int i = 0; i < innerVertexNum; ++i) {
816 if (tweakAlphaForCoverage) {
817 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
818 } else {
819 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
820 *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
821 }
822 }
823 }
824
825 struct BatchTracker {
826 SkMatrix fViewMatrix;
827 GrColor fColor;
828 bool fUsesLocalCoords;
829 bool fColorIgnored;
830 bool fCoverageIgnored;
831 bool fMiterStroke;
832 bool fCanTweakAlphaForCoverage;
833 };
834
835 BatchTracker fBatch;
836 const GrIndexBuffer* fIndexBuffer;
837 SkSTArray<1, Geometry, true> fGeoData;
838};
joshualitt4d8da812015-01-28 12:53:54 -0800839
840
joshualittb44293e2014-10-28 08:12:18 -0700841void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800842 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800843 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800844 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000845 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000846 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000847 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000848 bool miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700849 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000850 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700851 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000852 return;
853 }
854
joshualitt4283f132015-02-13 14:25:10 -0800855 AAStrokeRectBatch::Geometry geometry;
856 geometry.fColor = color;
857 geometry.fDevOutside = devOutside;
858 geometry.fDevOutsideAssist = devOutsideAssist;
859 geometry.fDevInside = devInside;
860 geometry.fMiterStroke = miterStroke;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000861
joshualitt4283f132015-02-13 14:25:10 -0800862 SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix, indexBuffer));
863 target->drawBatch(pipelineBuilder, batch);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000864}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000865
joshualittb44293e2014-10-28 08:12:18 -0700866void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800867 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800868 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800869 const SkMatrix& viewMatrix,
870 const SkRect rects[2]) {
871 SkASSERT(viewMatrix.rectStaysRect());
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000872 SkASSERT(!rects[1].isEmpty());
873
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000874 SkRect devOutside, devOutsideAssist, devInside;
joshualitt8059eb92014-12-29 15:10:07 -0800875 viewMatrix.mapRect(&devOutside, rects[0]);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000876 // can't call mapRect for devInside since it calls sort
joshualitt8059eb92014-12-29 15:10:07 -0800877 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000878
879 if (devInside.isEmpty()) {
egdaniel8dd688b2015-01-22 10:16:09 -0800880 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800881 devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000882 return;
883 }
884
egdaniel8dd688b2015-01-22 10:16:09 -0800885 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
886 devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000887}