blob: 7c34c25abd405dfd64a7c51ab61dd3e54627174a [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) {
joshualitt44701df2015-02-23 14:44:57 -0800514 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000515 return;
516 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000517
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000518 SkRect devInside(devRect);
519 devInside.inset(rx, ry);
520
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000521 SkRect devOutsideAssist(devRect);
522
523 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
524 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000525 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000526 if (!miterStroke) {
527 devOutside.inset(0, ry);
528 devOutsideAssist.outset(0, ry);
529 }
530
joshualitt4d8da812015-01-28 12:53:54 -0800531 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
532 devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000533}
534
joshualitt4283f132015-02-13 14:25:10 -0800535class AAStrokeRectBatch : public GrBatch {
536public:
537 // TODO support AA rotated stroke rects by copying around view matrices
538 struct Geometry {
539 GrColor fColor;
540 SkRect fDevOutside;
541 SkRect fDevOutsideAssist;
542 SkRect fDevInside;
543 bool fMiterStroke;
544 };
545
546 static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
547 const GrIndexBuffer* indexBuffer) {
548 return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix, indexBuffer));
joshualitt4d8da812015-01-28 12:53:54 -0800549 }
joshualitt4283f132015-02-13 14:25:10 -0800550
551 const char* name() const SK_OVERRIDE { return "AAStrokeRect"; }
552
553 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
554 // When this is called on a batch, there is only one geometry bundle
555 out->setKnownFourComponents(fGeoData[0].fColor);
556 }
557
558 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
559 out->setUnknownSingleComponent();
560 }
561
562 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
563 // Handle any color overrides
564 if (init.fColorIgnored) {
565 fGeoData[0].fColor = GrColor_ILLEGAL;
566 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
567 fGeoData[0].fColor = init.fOverrideColor;
568 }
569
570 // setup batch properties
571 fBatch.fColorIgnored = init.fColorIgnored;
572 fBatch.fColor = fGeoData[0].fColor;
573 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
574 fBatch.fCoverageIgnored = init.fCoverageIgnored;
575 fBatch.fMiterStroke = fGeoData[0].fMiterStroke;
576 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
577 }
578
579 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
580 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
581
582 // Local matrix is ignored if we don't have local coords. If we have localcoords we only
583 // batch with identical view matrices
584 SkMatrix localMatrix;
585 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
586 SkDebugf("Cannot invert\n");
587 return;
588 }
589
joshualitt332c7292015-02-23 08:44:31 -0800590 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
591 localMatrix));
joshualitt4283f132015-02-13 14:25:10 -0800592
593 batchTarget->initDraw(gp, pipeline);
594
595 // TODO this is hacky, but the only way we have to initialize the GP is to use the
596 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
597 // everywhere we can remove this nastiness
598 GrPipelineInfo init;
599 init.fColorIgnored = fBatch.fColorIgnored;
600 init.fOverrideColor = GrColor_ILLEGAL;
601 init.fCoverageIgnored = fBatch.fCoverageIgnored;
602 init.fUsesLocalCoords = this->usesLocalCoords();
603 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
604
605 size_t vertexStride = gp->getVertexStride();
606
607 SkASSERT(canTweakAlphaForCoverage ?
608 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
609 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
610
611 int innerVertexNum = 4;
612 int outerVertexNum = this->miterStroke() ? 4 : 8;
613 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
614
615 int instanceCount = fGeoData.count();
616 int vertexCount = totalVertexNum * instanceCount;
617
618 const GrVertexBuffer* vertexBuffer;
619 int firstVertex;
620
621 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
622 vertexCount,
623 &vertexBuffer,
624 &firstVertex);
625
626 for (int i = 0; i < instanceCount; i++) {
627 const Geometry& args = fGeoData[i];
628 this->generateAAStrokeRectGeometry(vertices,
629 i * totalVertexNum * vertexStride,
630 vertexStride,
631 outerVertexNum,
632 innerVertexNum,
633 args.fColor,
634 args.fDevOutside,
635 args.fDevOutsideAssist,
636 args.fDevInside,
637 args.fMiterStroke,
638 canTweakAlphaForCoverage);
639 }
640
641 GrDrawTarget::DrawInfo drawInfo;
642 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
643 drawInfo.setStartVertex(0);
644 drawInfo.setStartIndex(0);
645 drawInfo.setVerticesPerInstance(totalVertexNum);
646 drawInfo.setIndicesPerInstance(aa_stroke_rect_index_count(this->miterStroke()));
647 drawInfo.adjustStartVertex(firstVertex);
648 drawInfo.setVertexBuffer(vertexBuffer);
649 drawInfo.setIndexBuffer(fIndexBuffer);
650
651 int maxInstancesPerDraw = kNumBevelStrokeRectsInIndexBuffer;
652
653 while (instanceCount) {
654 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
655 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
656 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
657
658 batchTarget->draw(drawInfo);
659
660 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
661 instanceCount -= drawInfo.instanceCount();
662 }
663 }
664
665 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
666
667private:
668 AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix,
669 const GrIndexBuffer* indexBuffer)
670 : fIndexBuffer(indexBuffer) {
671 this->initClassID<AAStrokeRectBatch>();
672 fBatch.fViewMatrix = viewMatrix;
673 fGeoData.push_back(geometry);
674 }
675
676 GrColor color() const { return fBatch.fColor; }
677 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
678 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
679 bool colorIgnored() const { return fBatch.fColorIgnored; }
680 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
681 bool miterStroke() const { return fBatch.fMiterStroke; }
682
683 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
684 AAStrokeRectBatch* that = t->cast<AAStrokeRectBatch>();
685
686 // TODO batch across miterstroke changes
687 if (this->miterStroke() != that->miterStroke()) {
688 return false;
689 }
690
691 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
692 // local coords then we won't be able to batch. We could actually upload the viewmatrix
693 // using vertex attributes in these cases, but haven't investigated that
694 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
695 return false;
696 }
697
698 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
699 // not tweaking
700 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
701 fBatch.fCanTweakAlphaForCoverage = false;
702 }
703
704 if (this->color() != that->color()) {
705 fBatch.fColor = GrColor_ILLEGAL;
706 }
707 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
708 return true;
709 }
710
711 void generateAAStrokeRectGeometry(void* vertices,
712 size_t offset,
713 size_t vertexStride,
714 int outerVertexNum,
715 int innerVertexNum,
716 GrColor color,
717 const SkRect& devOutside,
718 const SkRect& devOutsideAssist,
719 const SkRect& devInside,
720 bool miterStroke,
721 bool tweakAlphaForCoverage) const {
722 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
723
724 // We create vertices for four nested rectangles. There are two ramps from 0 to full
725 // coverage, one on the exterior of the stroke and the other on the interior.
726 // The following pointers refer to the four rects, from outermost to innermost.
727 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
728 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vertexStride);
729 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vertexStride);
730 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts +
731 (2 * outerVertexNum + innerVertexNum) *
732 vertexStride);
733
734 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
735 // TODO: this only really works if the X & Y margins are the same all around
736 // the rect (or if they are all >= 1.0).
737 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
738 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
739 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
740 if (miterStroke) {
741 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
742 } else {
743 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom -
744 devInside.fBottom);
745 }
746 SkASSERT(inset >= 0);
747 #else
748 SkScalar inset = SK_ScalarHalf;
749 #endif
750
751 if (miterStroke) {
752 // outermost
753 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
754 // inner two
755 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
756 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
757 // innermost
758 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
759 } else {
760 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
761 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts +
762 (outerVertexNum + 4) *
763 vertexStride);
764 // outermost
765 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
766 set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf,
767 -SK_ScalarHalf);
768 // outer one of the inner two
769 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
770 set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset);
771 // inner one of the inner two
772 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
773 // innermost
774 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
775 }
776
777 // Make verts point to vertex color and then set all the color and coverage vertex attrs
778 // values. The outermost rect has 0 coverage
779 verts += sizeof(SkPoint);
780 for (int i = 0; i < outerVertexNum; ++i) {
781 if (tweakAlphaForCoverage) {
782 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
783 } else {
784 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
785 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
786 }
787 }
788
789 // scale is the coverage for the the inner two rects.
790 int scale;
791 if (inset < SK_ScalarHalf) {
792 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
793 SkASSERT(scale >= 0 && scale <= 255);
794 } else {
795 scale = 0xff;
796 }
797
798 float innerCoverage = GrNormalizeByteToFloat(scale);
799 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
800
801 verts += outerVertexNum * vertexStride;
802 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
803 if (tweakAlphaForCoverage) {
804 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
805 } else {
806 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
807 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
808 innerCoverage;
809 }
810 }
811
812 // The innermost rect has 0 coverage
813 verts += (outerVertexNum + innerVertexNum) * vertexStride;
814 for (int i = 0; i < innerVertexNum; ++i) {
815 if (tweakAlphaForCoverage) {
816 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
817 } else {
818 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
819 *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
820 }
821 }
822 }
823
824 struct BatchTracker {
825 SkMatrix fViewMatrix;
826 GrColor fColor;
827 bool fUsesLocalCoords;
828 bool fColorIgnored;
829 bool fCoverageIgnored;
830 bool fMiterStroke;
831 bool fCanTweakAlphaForCoverage;
832 };
833
834 BatchTracker fBatch;
835 const GrIndexBuffer* fIndexBuffer;
836 SkSTArray<1, Geometry, true> fGeoData;
837};
joshualitt4d8da812015-01-28 12:53:54 -0800838
839
joshualittb44293e2014-10-28 08:12:18 -0700840void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800841 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800842 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800843 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000844 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000845 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000846 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000847 bool miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700848 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000849 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700850 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000851 return;
852 }
853
joshualitt4283f132015-02-13 14:25:10 -0800854 AAStrokeRectBatch::Geometry geometry;
855 geometry.fColor = color;
856 geometry.fDevOutside = devOutside;
857 geometry.fDevOutsideAssist = devOutsideAssist;
858 geometry.fDevInside = devInside;
859 geometry.fMiterStroke = miterStroke;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000860
joshualitt4283f132015-02-13 14:25:10 -0800861 SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix, indexBuffer));
862 target->drawBatch(pipelineBuilder, batch);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000863}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000864
joshualittb44293e2014-10-28 08:12:18 -0700865void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800866 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800867 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800868 const SkMatrix& viewMatrix,
869 const SkRect rects[2]) {
870 SkASSERT(viewMatrix.rectStaysRect());
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000871 SkASSERT(!rects[1].isEmpty());
872
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000873 SkRect devOutside, devOutsideAssist, devInside;
joshualitt8059eb92014-12-29 15:10:07 -0800874 viewMatrix.mapRect(&devOutside, rects[0]);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000875 // can't call mapRect for devInside since it calls sort
joshualitt8059eb92014-12-29 15:10:07 -0800876 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000877
878 if (devInside.isEmpty()) {
joshualitt44701df2015-02-23 14:44:57 -0800879 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000880 return;
881 }
882
egdaniel8dd688b2015-01-22 10:16:09 -0800883 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
884 devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000885}