blob: 9ac2be2cbc53e4afd23154ee4bc6d0e45d9cea2a [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
73 if (!this->canTweakAlphaForCoverage() && GrColorIsOpaque(fGeoData[0].fColor)) {
74 out->setUnknownOpaqueFourComponents();
75 } else {
76 out->setUnknownFourComponents();
77 }
78 }
79
80 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
81 if (this->canTweakAlphaForCoverage()) {
82 // uniform coverage
83 out->setKnownSingleComponent(0xff);
84 } else {
85 out->setUnknownSingleComponent();
86 }
87 }
88
89 void initBatchOpt(const GrBatchOpt& batchOpt) {
90 fBatchOpt = batchOpt;
91 }
92
93 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
94 // Handle any color overrides
95 if (init.fColorIgnored) {
96 fGeoData[0].fColor = GrColor_ILLEGAL;
97 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
98 fGeoData[0].fColor = init.fOverrideColor;
99 }
100
101 // setup batch properties
102 fBatch.fColorIgnored = init.fColorIgnored;
103 fBatch.fColor = fGeoData[0].fColor;
104 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
105 fBatch.fCoverageIgnored = init.fCoverageIgnored;
106 }
107
108 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
109 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
110
111 SkMatrix localMatrix;
joshualitt68c7b6a2015-02-12 12:32:26 -0800112 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
joshualitt4d8da812015-01-28 12:53:54 -0800113 SkDebugf("Cannot invert\n");
114 return;
115 }
116
joshualitt68c7b6a2015-02-12 12:32:26 -0800117 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
118 localMatrix));
joshualitt4d8da812015-01-28 12:53:54 -0800119
120 batchTarget->initDraw(gp, pipeline);
joshualitt4d8da812015-01-28 12:53:54 -0800121
122 // TODO this is hacky, but the only way we have to initialize the GP is to use the
123 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
124 // everywhere we can remove this nastiness
125 GrPipelineInfo init;
126 init.fColorIgnored = fBatch.fColorIgnored;
127 init.fOverrideColor = GrColor_ILLEGAL;
128 init.fCoverageIgnored = fBatch.fCoverageIgnored;
129 init.fUsesLocalCoords = this->usesLocalCoords();
130 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
131
132 size_t vertexStride = gp->getVertexStride();
133
134 SkASSERT(canTweakAlphaForCoverage ?
135 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
136 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
137
138 int instanceCount = fGeoData.count();
139 int vertexCount = kVertsPerAAFillRect * instanceCount;
140
141 const GrVertexBuffer* vertexBuffer;
142 int firstVertex;
143
joshualitt68c7b6a2015-02-12 12:32:26 -0800144 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
joshualitt4d8da812015-01-28 12:53:54 -0800145 vertexCount,
146 &vertexBuffer,
147 &firstVertex);
148
149 for (int i = 0; i < instanceCount; i++) {
150 const Geometry& args = fGeoData[i];
151 this->generateAAFillRectGeometry(vertices,
joshualitt68c7b6a2015-02-12 12:32:26 -0800152 i * kVertsPerAAFillRect * vertexStride,
153 vertexStride,
154 args.fColor,
155 args.fViewMatrix,
156 args.fRect,
157 args.fDevRect,
158 canTweakAlphaForCoverage);
joshualitt4d8da812015-01-28 12:53:54 -0800159 }
160
161 GrDrawTarget::DrawInfo drawInfo;
162 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
163 drawInfo.setStartVertex(0);
164 drawInfo.setStartIndex(0);
165 drawInfo.setVerticesPerInstance(kVertsPerAAFillRect);
166 drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect);
167 drawInfo.adjustStartVertex(firstVertex);
168 drawInfo.setVertexBuffer(vertexBuffer);
169 drawInfo.setIndexBuffer(fIndexBuffer);
170
171 int maxInstancesPerDraw = kNumAAFillRectsInIndexBuffer;
172
173 while (instanceCount) {
174 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
175 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
176 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
177
178 batchTarget->draw(drawInfo);
179
180 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
181 instanceCount -= drawInfo.instanceCount();
182 }
183 }
184
185 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
186
187private:
188 AAFillRectBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
189 : fIndexBuffer(indexBuffer) {
190 this->initClassID<AAFillRectBatch>();
191 fGeoData.push_back(geometry);
192 }
193
194 GrColor color() const { return fBatch.fColor; }
195 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
196 bool canTweakAlphaForCoverage() const { return fBatchOpt.fCanTweakAlphaForCoverage; }
197 bool colorIgnored() const { return fBatch.fColorIgnored; }
198 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
199
200 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
201 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
joshualitt4d8da812015-01-28 12:53:54 -0800202
joshualitt68c7b6a2015-02-12 12:32:26 -0800203 SkASSERT(this->canTweakAlphaForCoverage() == that->canTweakAlphaForCoverage() &&
204 this->usesLocalCoords() == that->usesLocalCoords() &&
205 this->colorIgnored() == that->colorIgnored());
joshualitt4d8da812015-01-28 12:53:54 -0800206 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
207 // local coords then we won't be able to batch. We could actually upload the viewmatrix
208 // using vertex attributes in these cases, but haven't investigated that
209 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
210 return false;
211 }
212
213 if (this->color() != that->color()) {
214 fBatch.fColor = GrColor_ILLEGAL;
215 }
216 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
217 return true;
218 }
219
220 void generateAAFillRectGeometry(void* vertices,
bsalomon81aca542015-01-29 07:13:20 -0800221 size_t offset,
222 size_t vertexStride,
joshualitt4d8da812015-01-28 12:53:54 -0800223 GrColor color,
224 const SkMatrix& viewMatrix,
225 const SkRect& rect,
226 const SkRect& devRect,
227 bool tweakAlphaForCoverage) const {
228 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
229
230 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
231 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
232
233 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
234 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
235
236 if (viewMatrix.rectStaysRect()) {
237 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
238 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
239 } else {
240 // compute transformed (1, 0) and (0, 1) vectors
241 SkVector vec[2] = {
242 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
243 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
244 };
245
246 vec[0].normalize();
247 vec[0].scale(SK_ScalarHalf);
248 vec[1].normalize();
249 vec[1].scale(SK_ScalarHalf);
250
251 // create the rotated rect
252 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
253 rect.fRight, rect.fBottom, vertexStride);
254 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
255
256 // Now create the inset points and then outset the original
257 // rotated points
258
259 // TL
260 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
261 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
262 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
263 // BL
264 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
265 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
266 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
267 // BR
268 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
269 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
270 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
271 // TR
272 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
273 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
274 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
275 }
276
277 // Make verts point to vertex color and then set all the color and coverage vertex attrs
278 // values.
279 verts += sizeof(SkPoint);
280 for (int i = 0; i < 4; ++i) {
281 if (tweakAlphaForCoverage) {
282 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
283 } else {
284 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
285 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
286 }
287 }
288
289 int scale;
290 if (inset < SK_ScalarHalf) {
291 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
292 SkASSERT(scale >= 0 && scale <= 255);
293 } else {
294 scale = 0xff;
295 }
296
297 verts += 4 * vertexStride;
298
299 float innerCoverage = GrNormalizeByteToFloat(scale);
300 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
301
302 for (int i = 0; i < 4; ++i) {
303 if (tweakAlphaForCoverage) {
304 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
305 } else {
306 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
307 *reinterpret_cast<float*>(verts + i * vertexStride +
308 sizeof(GrColor)) = innerCoverage;
309 }
310 }
311 }
312
313 struct BatchTracker {
314 GrColor fColor;
315 bool fUsesLocalCoords;
316 bool fColorIgnored;
317 bool fCoverageIgnored;
318 };
319
320 GrBatchOpt fBatchOpt;
321 BatchTracker fBatch;
322 const GrIndexBuffer* fIndexBuffer;
323 SkSTArray<1, Geometry, true> fGeoData;
324};
325
326namespace {
327// Should the coverage be multiplied into the color attrib or use a separate attrib.
328enum CoverageAttribType {
329 kUseColor_CoverageAttribType,
330 kUseCoverage_CoverageAttribType,
331};
332}
333
334void GrAARectRenderer::reset() {
335 SkSafeSetNull(fAAFillRectIndexBuffer);
336 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
337 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
338}
339
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000340static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000341 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
342 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
343 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
344 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
345
346 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
347 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
348 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
349 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
350
351 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
352 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
353 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
354 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
355};
356
joshualitt5ead6da2014-10-22 16:00:29 -0700357static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
358static const int kVertsPerMiterStrokeRect = 16;
359static const int kNumMiterStrokeRectsInIndexBuffer = 256;
360
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000361/**
362 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
363 * from the first index. The index layout:
364 * outer AA line: 0~3, 4~7
365 * outer edge: 8~11, 12~15
366 * inner edge: 16~19
367 * inner AA line: 20~23
368 * Following comes a bevel-stroke rect and its indices:
369 *
370 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000371 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000372 * * ______________________________ *
373 * * / 12 15 \ *
374 * * / \ *
375 * 0 * |8 16_____________________19 11 | * 3
376 * * | | | | *
377 * * | | **************** | | *
378 * * | | * 20 23 * | | *
379 * * | | * * | | *
380 * * | | * 21 22 * | | *
381 * * | | **************** | | *
382 * * | |____________________| | *
383 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000384 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000385 * * \13 __________________________14/ *
386 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000387 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000388 * 5 6
389 */
390static const uint16_t gBevelStrokeAARectIdx[] = {
391 // Draw outer AA, from outer AA line to outer edge, shift is 0.
392 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
393 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
394 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
395 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
396 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
397 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
398 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
399 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
400
401 // Draw the stroke, from outer edge to inner edge, shift is 8.
402 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
403 1 + 8, 5 + 8, 9 + 8,
404 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
405 6 + 8, 2 + 8, 10 + 8,
406 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
407 3 + 8, 7 + 8, 11 + 8,
408 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
409 4 + 8, 0 + 8, 8 + 8,
410
411 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
412 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
413 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
414 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
415 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
416};
417
joshualitt5ead6da2014-10-22 16:00:29 -0700418static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
419static const int kVertsPerBevelStrokeRect = 24;
420static const int kNumBevelStrokeRectsInIndexBuffer = 256;
421
joshualittb44293e2014-10-28 08:12:18 -0700422static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000423 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
424 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000425}
426
joshualittb44293e2014-10-28 08:12:18 -0700427GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000428 if (miterStroke) {
429 if (NULL == fAAMiterStrokeRectIndexBuffer) {
430 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700431 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
432 kIndicesPerMiterStrokeRect,
433 kNumMiterStrokeRectsInIndexBuffer,
434 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000435 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000436 return fAAMiterStrokeRectIndexBuffer;
437 } else {
438 if (NULL == fAABevelStrokeRectIndexBuffer) {
439 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700440 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
441 kIndicesPerBevelStrokeRect,
442 kNumBevelStrokeRectsInIndexBuffer,
443 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000444 }
445 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000446 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000447}
448
joshualittb44293e2014-10-28 08:12:18 -0700449void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800450 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800451 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800452 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000453 const SkRect& rect,
bsalomon9c0822a2014-08-11 11:07:48 -0700454 const SkRect& devRect) {
joshualitt5ead6da2014-10-22 16:00:29 -0700455 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700456 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
457 kIndicesPerAAFillRect,
458 kNumAAFillRectsInIndexBuffer,
459 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700460 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000461
joshualitt4d8da812015-01-28 12:53:54 -0800462 AAFillRectBatch::Geometry geometry;
463 geometry.fRect = rect;
464 geometry.fViewMatrix = viewMatrix;
465 geometry.fDevRect = devRect;
466 geometry.fColor = color;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000467
joshualitt4d8da812015-01-28 12:53:54 -0800468 SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
469 target->drawBatch(pipelineBuilder, batch, &devRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000470}
471
joshualittb44293e2014-10-28 08:12:18 -0700472void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800473 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800474 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800475 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000476 const SkRect& rect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000477 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700478 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000479 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700480 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000481 if (width > 0) {
482 devStrokeSize.set(width, width);
joshualitt8059eb92014-12-29 15:10:07 -0800483 viewMatrix.mapVectors(&devStrokeSize, 1);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000484 devStrokeSize.setAbs(devStrokeSize);
485 } else {
486 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
487 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000488
robertphillips@google.com18136d12013-05-10 11:05:58 +0000489 const SkScalar dx = devStrokeSize.fX;
490 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000491 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
492 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000493
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000494 // Temporarily #if'ed out. We don't want to pass in the devRect but
495 // right now it is computed in GrContext::apply_aa_to_rect and we don't
496 // want to throw away the work
497#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000498 SkRect devRect;
499 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000500#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000501
bsalomon@google.com81712882012-11-01 17:12:34 +0000502 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000503 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000504 SkScalar w = devRect.width() - dx;
505 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000506 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000507 }
508
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000509 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000510 devOutside.outset(rx, ry);
511
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000512 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700513 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000514 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700515 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
516 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000517 miterStroke = false;
518 }
519
520 if (spare <= 0 && miterStroke) {
egdaniel8dd688b2015-01-22 10:16:09 -0800521 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800522 devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000523 return;
524 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000525
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000526 SkRect devInside(devRect);
527 devInside.inset(rx, ry);
528
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000529 SkRect devOutsideAssist(devRect);
530
531 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
532 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000533 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000534 if (!miterStroke) {
535 devOutside.inset(0, ry);
536 devOutsideAssist.outset(0, ry);
537 }
538
joshualitt4d8da812015-01-28 12:53:54 -0800539 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
540 devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000541}
542
joshualitt68c7b6a2015-02-12 12:32:26 -0800543class AAStrokeRectBatch : public GrBatch {
544public:
545 // TODO support AA rotated stroke rects by copying around view matrices
546 struct Geometry {
547 GrColor fColor;
548 SkRect fDevOutside;
549 SkRect fDevOutsideAssist;
550 SkRect fDevInside;
551 bool fMiterStroke;
552 };
553
554 static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
555 const GrIndexBuffer* indexBuffer) {
556 return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix, indexBuffer));
joshualitt4d8da812015-01-28 12:53:54 -0800557 }
joshualitt68c7b6a2015-02-12 12:32:26 -0800558
559 const char* name() const SK_OVERRIDE { return "AAStrokeRect"; }
560
561 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
562 // When this is called on a batch, there is only one geometry bundle
563 if (!this->canTweakAlphaForCoverage() && GrColorIsOpaque(fGeoData[0].fColor)) {
564 out->setUnknownOpaqueFourComponents();
565 } else {
566 out->setUnknownFourComponents();
567 }
568 }
569
570 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
571 if (this->canTweakAlphaForCoverage()) {
572 // uniform coverage
573 out->setKnownSingleComponent(0xff);
574 } else {
575 out->setUnknownSingleComponent();
576 }
577 }
578
579 void initBatchOpt(const GrBatchOpt& batchOpt) {
580 fBatchOpt = batchOpt;
581 }
582
583 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
584 // Handle any color overrides
585 if (init.fColorIgnored) {
586 fGeoData[0].fColor = GrColor_ILLEGAL;
587 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
588 fGeoData[0].fColor = init.fOverrideColor;
589 }
590
591 // setup batch properties
592 fBatch.fColorIgnored = init.fColorIgnored;
593 fBatch.fColor = fGeoData[0].fColor;
594 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
595 fBatch.fCoverageIgnored = init.fCoverageIgnored;
596 fBatch.fMiterStroke = fGeoData[0].fMiterStroke;
597 }
598
599 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
600 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
601
602 // Local matrix is ignored if we don't have local coords. If we have localcoords we only
603 // batch with identical view matrices
604 SkMatrix localMatrix;
605 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
606 SkDebugf("Cannot invert\n");
607 return;
608 }
609
610 SkAutoTUnref<const GrGeometryProcessor>gp(create_fill_rect_gp(canTweakAlphaForCoverage,
611 localMatrix));
612
613 batchTarget->initDraw(gp, pipeline);
614
615 // TODO this is hacky, but the only way we have to initialize the GP is to use the
616 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
617 // everywhere we can remove this nastiness
618 GrPipelineInfo init;
619 init.fColorIgnored = fBatch.fColorIgnored;
620 init.fOverrideColor = GrColor_ILLEGAL;
621 init.fCoverageIgnored = fBatch.fCoverageIgnored;
622 init.fUsesLocalCoords = this->usesLocalCoords();
623 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
624
625 size_t vertexStride = gp->getVertexStride();
626
627 SkASSERT(canTweakAlphaForCoverage ?
628 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
629 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
630
631 int innerVertexNum = 4;
632 int outerVertexNum = this->miterStroke() ? 4 : 8;
633 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
634
635 int instanceCount = fGeoData.count();
636 int vertexCount = totalVertexNum * instanceCount;
637
638 const GrVertexBuffer* vertexBuffer;
639 int firstVertex;
640
641 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
642 vertexCount,
643 &vertexBuffer,
644 &firstVertex);
645
646 for (int i = 0; i < instanceCount; i++) {
647 const Geometry& args = fGeoData[i];
648 this->generateAAStrokeRectGeometry(vertices,
649 i * totalVertexNum * vertexStride,
650 vertexStride,
651 outerVertexNum,
652 innerVertexNum,
653 args.fColor,
654 args.fDevOutside,
655 args.fDevOutsideAssist,
656 args.fDevInside,
657 args.fMiterStroke,
658 canTweakAlphaForCoverage);
659 }
660
661 GrDrawTarget::DrawInfo drawInfo;
662 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
663 drawInfo.setStartVertex(0);
664 drawInfo.setStartIndex(0);
665 drawInfo.setVerticesPerInstance(totalVertexNum);
666 drawInfo.setIndicesPerInstance(aa_stroke_rect_index_count(this->miterStroke()));
667 drawInfo.adjustStartVertex(firstVertex);
668 drawInfo.setVertexBuffer(vertexBuffer);
669 drawInfo.setIndexBuffer(fIndexBuffer);
670
671 int maxInstancesPerDraw = kNumBevelStrokeRectsInIndexBuffer;
672
673 while (instanceCount) {
674 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
675 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
676 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
677
678 batchTarget->draw(drawInfo);
679
680 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
681 instanceCount -= drawInfo.instanceCount();
682 }
683 }
684
685 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
686
687private:
688 AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix,
689 const GrIndexBuffer* indexBuffer)
690 : fIndexBuffer(indexBuffer) {
691 this->initClassID<AAStrokeRectBatch>();
692 fBatch.fViewMatrix = viewMatrix;
693 fGeoData.push_back(geometry);
694 }
695
696 GrColor color() const { return fBatch.fColor; }
697 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
698 bool canTweakAlphaForCoverage() const { return fBatchOpt.fCanTweakAlphaForCoverage; }
699 bool colorIgnored() const { return fBatch.fColorIgnored; }
700 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
701 bool miterStroke() const { return fBatch.fMiterStroke; }
702
703 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
704 AAStrokeRectBatch* that = t->cast<AAStrokeRectBatch>();
705
706 // TODO batch across miterstroke changes
707 if (this->miterStroke() != that->miterStroke()) {
708 return false;
709 }
710
711 SkASSERT(this->canTweakAlphaForCoverage() == that->canTweakAlphaForCoverage() &&
712 this->usesLocalCoords() == that->usesLocalCoords() &&
713 this->colorIgnored() == that->colorIgnored());
714 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
715 // local coords then we won't be able to batch. We could actually upload the viewmatrix
716 // using vertex attributes in these cases, but haven't investigated that
717 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
718 return false;
719 }
720
721 if (this->color() != that->color()) {
722 fBatch.fColor = GrColor_ILLEGAL;
723 }
724 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
725 return true;
726 }
727
728 void generateAAStrokeRectGeometry(void* vertices,
729 uint32_t offset,
joshualittc63de322015-02-12 13:01:52 -0800730 uint32_t vertexStride,
joshualitt68c7b6a2015-02-12 12:32:26 -0800731 int outerVertexNum,
732 int innerVertexNum,
733 GrColor color,
734 const SkRect& devOutside,
735 const SkRect& devOutsideAssist,
736 const SkRect& devInside,
737 bool miterStroke,
738 bool tweakAlphaForCoverage) const {
739 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
740
741 // We create vertices for four nested rectangles. There are two ramps from 0 to full
742 // coverage, one on the exterior of the stroke and the other on the interior.
743 // The following pointers refer to the four rects, from outermost to innermost.
744 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
745 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vertexStride);
746 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vertexStride);
747 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts +
748 (2 * outerVertexNum + innerVertexNum) *
749 vertexStride);
750
751 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
752 // TODO: this only really works if the X & Y margins are the same all around
753 // the rect (or if they are all >= 1.0).
754 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
755 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
756 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
757 if (miterStroke) {
758 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
759 } else {
760 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom -
761 devInside.fBottom);
762 }
763 SkASSERT(inset >= 0);
764 #else
765 SkScalar inset = SK_ScalarHalf;
766 #endif
767
768 if (miterStroke) {
769 // outermost
770 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
771 // inner two
772 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
773 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
774 // innermost
775 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
776 } else {
777 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
778 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts +
779 (outerVertexNum + 4) *
780 vertexStride);
781 // outermost
782 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
783 set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf,
784 -SK_ScalarHalf);
785 // outer one of the inner two
786 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset);
787 set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset, inset);
788 // inner one of the inner two
789 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset);
790 // innermost
791 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK_ScalarHalf);
792 }
793
794 // Make verts point to vertex color and then set all the color and coverage vertex attrs
795 // values. The outermost rect has 0 coverage
796 verts += sizeof(SkPoint);
797 for (int i = 0; i < outerVertexNum; ++i) {
798 if (tweakAlphaForCoverage) {
799 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
800 } else {
801 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
802 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
803 }
804 }
805
806 // scale is the coverage for the the inner two rects.
807 int scale;
808 if (inset < SK_ScalarHalf) {
809 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
810 SkASSERT(scale >= 0 && scale <= 255);
811 } else {
812 scale = 0xff;
813 }
814
815 float innerCoverage = GrNormalizeByteToFloat(scale);
816 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
817
818 verts += outerVertexNum * vertexStride;
819 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
820 if (tweakAlphaForCoverage) {
821 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
822 } else {
823 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
824 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
825 innerCoverage;
826 }
827 }
828
829 // The innermost rect has 0 coverage
830 verts += (outerVertexNum + innerVertexNum) * vertexStride;
831 for (int i = 0; i < innerVertexNum; ++i) {
832 if (tweakAlphaForCoverage) {
833 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
834 } else {
835 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
836 *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
837 }
838 }
839 }
840
841 struct BatchTracker {
842 SkMatrix fViewMatrix;
843 GrColor fColor;
844 bool fUsesLocalCoords;
845 bool fColorIgnored;
846 bool fCoverageIgnored;
847 bool fMiterStroke;
848 };
849
850 GrBatchOpt fBatchOpt;
851 BatchTracker fBatch;
852 const GrIndexBuffer* fIndexBuffer;
853 SkSTArray<1, Geometry, true> fGeoData;
854};
joshualitt4d8da812015-01-28 12:53:54 -0800855
856
joshualittb44293e2014-10-28 08:12:18 -0700857void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800858 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800859 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800860 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000861 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000862 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000863 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000864 bool miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700865 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000866 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700867 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000868 return;
869 }
870
joshualitt68c7b6a2015-02-12 12:32:26 -0800871 AAStrokeRectBatch::Geometry geometry;
872 geometry.fColor = color;
873 geometry.fDevOutside = devOutside;
874 geometry.fDevOutsideAssist = devOutsideAssist;
875 geometry.fDevInside = devInside;
876 geometry.fMiterStroke = miterStroke;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000877
joshualitt68c7b6a2015-02-12 12:32:26 -0800878 SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix, indexBuffer));
879 target->drawBatch(pipelineBuilder, batch);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000880}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000881
joshualittb44293e2014-10-28 08:12:18 -0700882void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800883 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800884 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800885 const SkMatrix& viewMatrix,
886 const SkRect rects[2]) {
887 SkASSERT(viewMatrix.rectStaysRect());
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000888 SkASSERT(!rects[1].isEmpty());
889
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000890 SkRect devOutside, devOutsideAssist, devInside;
joshualitt8059eb92014-12-29 15:10:07 -0800891 viewMatrix.mapRect(&devOutside, rects[0]);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000892 // can't call mapRect for devInside since it calls sort
joshualitt8059eb92014-12-29 15:10:07 -0800893 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000894
895 if (devInside.isEmpty()) {
egdaniel8dd688b2015-01-22 10:16:09 -0800896 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800897 devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000898 return;
899 }
900
egdaniel8dd688b2015-01-22 10:16:09 -0800901 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
902 devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000903}