6affc927ac6de376cd25c9f8c5bbc8b2fa97eb5b
[platform/upstream/libSkiaSharp.git] / src / gpu / GrAARectRenderer.cpp
1 /*
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"
9 #include "GrBatch.h"
10 #include "GrBatchTarget.h"
11 #include "GrBufferAllocPool.h"
12 #include "GrDefaultGeoProcFactory.h"
13 #include "GrGeometryProcessor.h"
14 #include "GrGpu.h"
15 #include "GrInvariantOutput.h"
16 #include "SkColorPriv.h"
17 #include "gl/GrGLProcessor.h"
18 #include "gl/GrGLGeometryProcessor.h"
19 #include "gl/builders/GrGLProgramBuilder.h"
20
21 ///////////////////////////////////////////////////////////////////////////////
22
23 static void set_inset_fan(SkPoint* pts, size_t stride,
24                           const SkRect& r, SkScalar dx, SkScalar dy) {
25     pts->setRectFan(r.fLeft + dx, r.fTop + dy,
26                     r.fRight - dx, r.fBottom - dy, stride);
27 }
28
29 static const uint16_t gFillAARectIdx[] = {
30     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
37 static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
38 static const int kVertsPerAAFillRect = 8;
39 static const int kNumAAFillRectsInIndexBuffer = 256;
40
41 static 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
56 class AAFillRectBatch : public GrBatch {
57 public:
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         out->setKnownFourComponents(fGeoData[0].fColor);
74     }
75
76     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
77         out->setUnknownSingleComponent();
78     }
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;
93         fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
94     }
95
96     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
97         bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
98
99         SkMatrix localMatrix;
100         if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
101             SkDebugf("Cannot invert\n");
102             return;
103         }
104
105         SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
106                                                                        localMatrix));
107
108         batchTarget->initDraw(gp, pipeline);
109
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
132         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
133                                                               vertexCount,
134                                                               &vertexBuffer,
135                                                               &firstVertex);
136
137         if (!vertices) {
138             SkDebugf("Could not allocate vertices\n");
139             return;
140         }
141
142         for (int i = 0; i < instanceCount; i++) {
143             const Geometry& args = fGeoData[i];
144             this->generateAAFillRectGeometry(vertices,
145                                              i * kVertsPerAAFillRect * vertexStride,
146                                              vertexStride,
147                                              args.fColor,
148                                              args.fViewMatrix,
149                                              args.fRect,
150                                              args.fDevRect,
151                                              canTweakAlphaForCoverage);
152         }
153
154         GrDrawTarget::DrawInfo drawInfo;
155         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
156         drawInfo.setStartVertex(0);
157         drawInfo.setStartIndex(0);
158         drawInfo.setVerticesPerInstance(kVertsPerAAFillRect);
159         drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect);
160         drawInfo.adjustStartVertex(firstVertex);
161         drawInfo.setVertexBuffer(vertexBuffer);
162         drawInfo.setIndexBuffer(fIndexBuffer);
163
164         int maxInstancesPerDraw = kNumAAFillRectsInIndexBuffer;
165
166         while (instanceCount) {
167             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
168             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
169             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
170
171             batchTarget->draw(drawInfo);
172
173             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
174             instanceCount -= drawInfo.instanceCount();
175         }
176     }
177
178     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
179
180 private:
181     AAFillRectBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
182         : fIndexBuffer(indexBuffer) {
183         this->initClassID<AAFillRectBatch>();
184         fGeoData.push_back(geometry);
185     }
186
187     GrColor color() const { return fBatch.fColor; }
188     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
189     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
190     bool colorIgnored() const { return fBatch.fColorIgnored; }
191     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
192
193     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
194         AAFillRectBatch* that = t->cast<AAFillRectBatch>();
195
196         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
197         // We apply the viewmatrix to the rect points on the cpu.  However, if the pipeline uses
198         // local coords then we won't be able to batch.  We could actually upload the viewmatrix
199         // using vertex attributes in these cases, but haven't investigated that
200         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
201             return false;
202         }
203
204         if (this->color() != that->color()) {
205             fBatch.fColor = GrColor_ILLEGAL;
206         }
207
208         // In the event of two batches, one who can tweak, one who cannot, we just fall back to
209         // not tweaking
210         if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
211             fBatch.fCanTweakAlphaForCoverage = false;
212         }
213
214         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
215         return true;
216     }
217
218     void generateAAFillRectGeometry(void* vertices,
219                                     size_t offset,
220                                     size_t vertexStride,
221                                     GrColor color,
222                                     const SkMatrix& viewMatrix,
223                                     const SkRect& rect,
224                                     const SkRect& devRect,
225                                     bool tweakAlphaForCoverage) const {
226         intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
227
228         SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
229         SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
230
231         SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
232         inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
233
234         if (viewMatrix.rectStaysRect()) {
235             set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
236             set_inset_fan(fan1Pos, vertexStride, devRect, inset,  inset);
237         } else {
238             // compute transformed (1, 0) and (0, 1) vectors
239             SkVector vec[2] = {
240               { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
241               { viewMatrix[SkMatrix::kMSkewX],  viewMatrix[SkMatrix::kMScaleY] }
242             };
243
244             vec[0].normalize();
245             vec[0].scale(SK_ScalarHalf);
246             vec[1].normalize();
247             vec[1].scale(SK_ScalarHalf);
248
249             // create the rotated rect
250             fan0Pos->setRectFan(rect.fLeft, rect.fTop,
251                                 rect.fRight, rect.fBottom, vertexStride);
252             viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
253
254             // Now create the inset points and then outset the original
255             // rotated points
256
257             // TL
258             *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
259                 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
260             *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
261             // BL
262             *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
263                 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
264             *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
265             // BR
266             *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
267                 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
268             *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
269             // TR
270             *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
271                 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
272             *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
273         }
274
275         // Make verts point to vertex color and then set all the color and coverage vertex attrs
276         // values.
277         verts += sizeof(SkPoint);
278         for (int i = 0; i < 4; ++i) {
279             if (tweakAlphaForCoverage) {
280                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
281             } else {
282                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
283                 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
284             }
285         }
286
287         int scale;
288         if (inset < SK_ScalarHalf) {
289             scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
290             SkASSERT(scale >= 0 && scale <= 255);
291         } else {
292             scale = 0xff;
293         }
294
295         verts += 4 * vertexStride;
296
297         float innerCoverage = GrNormalizeByteToFloat(scale);
298         GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
299
300         for (int i = 0; i < 4; ++i) {
301             if (tweakAlphaForCoverage) {
302                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
303             } else {
304                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
305                 *reinterpret_cast<float*>(verts + i * vertexStride +
306                                           sizeof(GrColor)) = innerCoverage;
307             }
308         }
309     }
310
311     struct BatchTracker {
312         GrColor fColor;
313         bool fUsesLocalCoords;
314         bool fColorIgnored;
315         bool fCoverageIgnored;
316         bool fCanTweakAlphaForCoverage;
317     };
318
319     BatchTracker fBatch;
320     const GrIndexBuffer* fIndexBuffer;
321     SkSTArray<1, Geometry, true> fGeoData;
322 };
323
324 namespace {
325 // Should the coverage be multiplied into the color attrib or use a separate attrib.
326 enum CoverageAttribType {
327     kUseColor_CoverageAttribType,
328     kUseCoverage_CoverageAttribType,
329 };
330 }
331
332 void GrAARectRenderer::reset() {
333     SkSafeSetNull(fAAFillRectIndexBuffer);
334     SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
335     SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
336 }
337
338 static const uint16_t gMiterStrokeAARectIdx[] = {
339     0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
340     1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
341     2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
342     3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
343
344     0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
345     1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
346     2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
347     3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
348
349     0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
350     1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
351     2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
352     3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
353 };
354
355 static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
356 static const int kVertsPerMiterStrokeRect = 16;
357 static const int kNumMiterStrokeRectsInIndexBuffer = 256;
358
359 /**
360  * As in miter-stroke, index = a + b, and a is the current index, b is the shift
361  * from the first index. The index layout:
362  * outer AA line: 0~3, 4~7
363  * outer edge:    8~11, 12~15
364  * inner edge:    16~19
365  * inner AA line: 20~23
366  * Following comes a bevel-stroke rect and its indices:
367  *
368  *           4                                 7
369  *            *********************************
370  *          *   ______________________________  *
371  *         *  / 12                          15 \  *
372  *        *  /                                  \  *
373  *     0 *  |8     16_____________________19  11 |  * 3
374  *       *  |       |                    |       |  *
375  *       *  |       |  ****************  |       |  *
376  *       *  |       |  * 20        23 *  |       |  *
377  *       *  |       |  *              *  |       |  *
378  *       *  |       |  * 21        22 *  |       |  *
379  *       *  |       |  ****************  |       |  *
380  *       *  |       |____________________|       |  *
381  *     1 *  |9    17                      18   10|  * 2
382  *        *  \                                  /  *
383  *         *  \13 __________________________14/  *
384  *          *                                   *
385  *           **********************************
386  *          5                                  6
387  */
388 static const uint16_t gBevelStrokeAARectIdx[] = {
389     // Draw outer AA, from outer AA line to outer edge, shift is 0.
390     0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
391     1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
392     5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
393     6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
394     2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
395     3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
396     7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
397     4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
398
399     // Draw the stroke, from outer edge to inner edge, shift is 8.
400     0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
401     1 + 8, 5 + 8, 9 + 8,
402     5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
403     6 + 8, 2 + 8, 10 + 8,
404     2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
405     3 + 8, 7 + 8, 11 + 8,
406     7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
407     4 + 8, 0 + 8, 8 + 8,
408
409     // Draw the inner AA, from inner edge to inner AA line, shift is 16.
410     0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
411     1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
412     2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
413     3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
414 };
415
416 static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
417 static const int kVertsPerBevelStrokeRect = 24;
418 static const int kNumBevelStrokeRectsInIndexBuffer = 256;
419
420 static int aa_stroke_rect_index_count(bool miterStroke) {
421     return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
422                          SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
423 }
424
425 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
426     if (miterStroke) {
427         if (NULL == fAAMiterStrokeRectIndexBuffer) {
428             fAAMiterStrokeRectIndexBuffer =
429                     fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
430                                                      kIndicesPerMiterStrokeRect,
431                                                      kNumMiterStrokeRectsInIndexBuffer,
432                                                      kVertsPerMiterStrokeRect);
433         }
434         return fAAMiterStrokeRectIndexBuffer;
435     } else {
436         if (NULL == fAABevelStrokeRectIndexBuffer) {
437             fAABevelStrokeRectIndexBuffer =
438                     fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
439                                                      kIndicesPerBevelStrokeRect,
440                                                      kNumBevelStrokeRectsInIndexBuffer,
441                                                      kVertsPerBevelStrokeRect);
442         }
443         return fAABevelStrokeRectIndexBuffer;
444     }
445 }
446
447 void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
448                                           GrPipelineBuilder* pipelineBuilder,
449                                           GrColor color,
450                                           const SkMatrix& viewMatrix,
451                                           const SkRect& rect,
452                                           const SkRect& devRect) {
453     if (!fAAFillRectIndexBuffer) {
454         fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
455                                                                   kIndicesPerAAFillRect,
456                                                                   kNumAAFillRectsInIndexBuffer,
457                                                                   kVertsPerAAFillRect);
458     }
459
460     if (!fAAFillRectIndexBuffer) {
461         SkDebugf("Unable to create index buffer\n");
462         return;
463     }
464
465     AAFillRectBatch::Geometry geometry;
466     geometry.fRect = rect;
467     geometry.fViewMatrix = viewMatrix;
468     geometry.fDevRect = devRect;
469     geometry.fColor = color;
470
471     SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
472     target->drawBatch(pipelineBuilder, batch, &devRect);
473 }
474
475 void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
476                                     GrPipelineBuilder* pipelineBuilder,
477                                     GrColor color,
478                                     const SkMatrix& viewMatrix,
479                                     const SkRect& rect,
480                                     const SkRect& devRect,
481                                     const SkStrokeRec& stroke) {
482     SkVector devStrokeSize;
483     SkScalar width = stroke.getWidth();
484     if (width > 0) {
485         devStrokeSize.set(width, width);
486         viewMatrix.mapVectors(&devStrokeSize, 1);
487         devStrokeSize.setAbs(devStrokeSize);
488     } else {
489         devStrokeSize.set(SK_Scalar1, SK_Scalar1);
490     }
491
492     const SkScalar dx = devStrokeSize.fX;
493     const SkScalar dy = devStrokeSize.fY;
494     const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
495     const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
496
497     // Temporarily #if'ed out. We don't want to pass in the devRect but
498     // right now it is computed in GrContext::apply_aa_to_rect and we don't
499     // want to throw away the work
500 #if 0
501     SkRect devRect;
502     combinedMatrix.mapRect(&devRect, rect);
503 #endif
504
505     SkScalar spare;
506     {
507         SkScalar w = devRect.width() - dx;
508         SkScalar h = devRect.height() - dy;
509         spare = SkTMin(w, h);
510     }
511
512     SkRect devOutside(devRect);
513     devOutside.outset(rx, ry);
514
515     bool miterStroke = true;
516     // For hairlines, make bevel and round joins appear the same as mitered ones.
517     // small miter limit means right angles show bevel...
518     if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
519                         stroke.getMiter() < SK_ScalarSqrt2)) {
520         miterStroke = false;
521     }
522
523     if (spare <= 0 && miterStroke) {
524         this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
525         return;
526     }
527
528     SkRect devInside(devRect);
529     devInside.inset(rx, ry);
530
531     SkRect devOutsideAssist(devRect);
532
533     // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
534     // to draw the outer of the rect. Because there are 8 vertices on the outer
535     // edge, while vertex number of inner edge is 4, the same as miter-stroke.
536     if (!miterStroke) {
537         devOutside.inset(0, ry);
538         devOutsideAssist.outset(0, ry);
539     }
540
541     this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
542                                devOutsideAssist, devInside, miterStroke);
543 }
544
545 class AAStrokeRectBatch : public GrBatch {
546 public:
547     // TODO support AA rotated stroke rects by copying around view matrices
548     struct Geometry {
549         GrColor fColor;
550         SkRect fDevOutside;
551         SkRect fDevOutsideAssist;
552         SkRect fDevInside;
553         bool fMiterStroke;
554     };
555
556     static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix,
557                            const GrIndexBuffer* indexBuffer) {
558         return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix, indexBuffer));
559     }
560
561     const char* name() const SK_OVERRIDE { return "AAStrokeRect"; }
562
563     void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
564         // When this is called on a batch, there is only one geometry bundle
565         out->setKnownFourComponents(fGeoData[0].fColor);
566     }
567
568     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
569         out->setUnknownSingleComponent();
570     }
571
572     void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
573         // Handle any color overrides
574         if (init.fColorIgnored) {
575             fGeoData[0].fColor = GrColor_ILLEGAL;
576         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
577             fGeoData[0].fColor = init.fOverrideColor;
578         }
579
580         // setup batch properties
581         fBatch.fColorIgnored = init.fColorIgnored;
582         fBatch.fColor = fGeoData[0].fColor;
583         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
584         fBatch.fCoverageIgnored = init.fCoverageIgnored;
585         fBatch.fMiterStroke = fGeoData[0].fMiterStroke;
586         fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
587     }
588
589     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
590         bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
591
592         // Local matrix is ignored if we don't have local coords.  If we have localcoords we only
593         // batch with identical view matrices
594         SkMatrix localMatrix;
595         if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
596             SkDebugf("Cannot invert\n");
597             return;
598         }
599
600         SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakAlphaForCoverage,
601                                                                        localMatrix));
602
603         batchTarget->initDraw(gp, pipeline);
604
605         // TODO this is hacky, but the only way we have to initialize the GP is to use the
606         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
607         // everywhere we can remove this nastiness
608         GrPipelineInfo init;
609         init.fColorIgnored = fBatch.fColorIgnored;
610         init.fOverrideColor = GrColor_ILLEGAL;
611         init.fCoverageIgnored = fBatch.fCoverageIgnored;
612         init.fUsesLocalCoords = this->usesLocalCoords();
613         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
614
615         size_t vertexStride = gp->getVertexStride();
616
617         SkASSERT(canTweakAlphaForCoverage ?
618                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
619                  vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
620
621         int innerVertexNum = 4;
622         int outerVertexNum = this->miterStroke() ? 4 : 8;
623         int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
624
625         int instanceCount = fGeoData.count();
626         int vertexCount = totalVertexNum * instanceCount;
627
628         const GrVertexBuffer* vertexBuffer;
629         int firstVertex;
630
631         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
632                                                               vertexCount,
633                                                               &vertexBuffer,
634                                                               &firstVertex);
635
636         if (!vertices) {
637             SkDebugf("Could not allocate vertices\n");
638             return;
639         }
640
641         for (int i = 0; i < instanceCount; i++) {
642             const Geometry& args = fGeoData[i];
643             this->generateAAStrokeRectGeometry(vertices,
644                                                i * totalVertexNum * vertexStride,
645                                                vertexStride,
646                                                outerVertexNum,
647                                                innerVertexNum,
648                                                args.fColor,
649                                                args.fDevOutside,
650                                                args.fDevOutsideAssist,
651                                                args.fDevInside,
652                                                args.fMiterStroke,
653                                                canTweakAlphaForCoverage);
654         }
655
656         GrDrawTarget::DrawInfo drawInfo;
657         drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
658         drawInfo.setStartVertex(0);
659         drawInfo.setStartIndex(0);
660         drawInfo.setVerticesPerInstance(totalVertexNum);
661         drawInfo.setIndicesPerInstance(aa_stroke_rect_index_count(this->miterStroke()));
662         drawInfo.adjustStartVertex(firstVertex);
663         drawInfo.setVertexBuffer(vertexBuffer);
664         drawInfo.setIndexBuffer(fIndexBuffer);
665
666         int maxInstancesPerDraw = kNumBevelStrokeRectsInIndexBuffer;
667
668         while (instanceCount) {
669             drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
670             drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
671             drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
672
673             batchTarget->draw(drawInfo);
674
675             drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
676             instanceCount -= drawInfo.instanceCount();
677         }
678     }
679
680     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
681
682 private:
683     AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix,
684                       const GrIndexBuffer* indexBuffer)
685         : fIndexBuffer(indexBuffer) {
686         this->initClassID<AAStrokeRectBatch>();
687         fBatch.fViewMatrix = viewMatrix;
688         fGeoData.push_back(geometry);
689     }
690
691     GrColor color() const { return fBatch.fColor; }
692     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
693     bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
694     bool colorIgnored() const { return fBatch.fColorIgnored; }
695     const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
696     bool miterStroke() const { return fBatch.fMiterStroke; }
697
698     bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
699         AAStrokeRectBatch* that = t->cast<AAStrokeRectBatch>();
700
701         // TODO batch across miterstroke changes
702         if (this->miterStroke() != that->miterStroke()) {
703             return false;
704         }
705
706         // We apply the viewmatrix to the rect points on the cpu.  However, if the pipeline uses
707         // local coords then we won't be able to batch.  We could actually upload the viewmatrix
708         // using vertex attributes in these cases, but haven't investigated that
709         if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
710             return false;
711         }
712
713         // In the event of two batches, one who can tweak, one who cannot, we just fall back to
714         // not tweaking
715         if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
716             fBatch.fCanTweakAlphaForCoverage = false;
717         }
718
719         if (this->color() != that->color()) {
720             fBatch.fColor = GrColor_ILLEGAL;
721         }
722         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
723         return true;
724     }
725
726     void generateAAStrokeRectGeometry(void* vertices,
727                                       size_t offset,
728                                       size_t vertexStride,
729                                       int outerVertexNum,
730                                       int innerVertexNum,
731                                       GrColor color,
732                                       const SkRect& devOutside,
733                                       const SkRect& devOutsideAssist,
734                                       const SkRect& devInside,
735                                       bool miterStroke,
736                                       bool tweakAlphaForCoverage) const {
737         intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
738
739         // We create vertices for four nested rectangles. There are two ramps from 0 to full
740         // coverage, one on the exterior of the stroke and the other on the interior.
741         // The following pointers refer to the four rects, from outermost to innermost.
742         SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
743         SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vertexStride);
744         SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vertexStride);
745         SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts +
746                                                       (2 * outerVertexNum + innerVertexNum) *
747                                                       vertexStride);
748
749     #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
750         // TODO: this only really works if the X & Y margins are the same all around
751         // the rect (or if they are all >= 1.0).
752         SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
753         inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
754         inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
755         if (miterStroke) {
756             inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
757         } else {
758             inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom -
759                                                        devInside.fBottom);
760         }
761         SkASSERT(inset >= 0);
762     #else
763         SkScalar inset = SK_ScalarHalf;
764     #endif
765
766         if (miterStroke) {
767             // outermost
768             set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
769             // inner two
770             set_inset_fan(fan1Pos, vertexStride, devOutside,  inset,  inset);
771             set_inset_fan(fan2Pos, vertexStride, devInside,  -inset, -inset);
772             // innermost
773             set_inset_fan(fan3Pos, vertexStride, devInside,   SK_ScalarHalf,  SK_ScalarHalf);
774         } else {
775             SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
776             SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts +
777                                                                 (outerVertexNum + 4) *
778                                                                 vertexStride);
779             // outermost
780             set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
781             set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_ScalarHalf,
782                           -SK_ScalarHalf);
783             // outer one of the inner two
784             set_inset_fan(fan1Pos, vertexStride, devOutside,  inset,  inset);
785             set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist,  inset,  inset);
786             // inner one of the inner two
787             set_inset_fan(fan2Pos, vertexStride, devInside,  -inset, -inset);
788             // innermost
789             set_inset_fan(fan3Pos, vertexStride, devInside,   SK_ScalarHalf,  SK_ScalarHalf);
790         }
791
792         // Make verts point to vertex color and then set all the color and coverage vertex attrs
793         // values. The outermost rect has 0 coverage
794         verts += sizeof(SkPoint);
795         for (int i = 0; i < outerVertexNum; ++i) {
796             if (tweakAlphaForCoverage) {
797                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
798             } else {
799                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
800                 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
801             }
802         }
803
804         // scale is the coverage for the the inner two rects.
805         int scale;
806         if (inset < SK_ScalarHalf) {
807             scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
808             SkASSERT(scale >= 0 && scale <= 255);
809         } else {
810             scale = 0xff;
811         }
812
813         float innerCoverage = GrNormalizeByteToFloat(scale);
814         GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
815
816         verts += outerVertexNum * vertexStride;
817         for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
818             if (tweakAlphaForCoverage) {
819                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
820             } else {
821                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
822                 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) =
823                         innerCoverage;
824             }
825         }
826
827         // The innermost rect has 0 coverage
828         verts += (outerVertexNum + innerVertexNum) * vertexStride;
829         for (int i = 0; i < innerVertexNum; ++i) {
830             if (tweakAlphaForCoverage) {
831                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
832             } else {
833                 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
834                 *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
835             }
836         }
837     }
838
839     struct BatchTracker {
840         SkMatrix fViewMatrix;
841         GrColor fColor;
842         bool fUsesLocalCoords;
843         bool fColorIgnored;
844         bool fCoverageIgnored;
845         bool fMiterStroke;
846         bool fCanTweakAlphaForCoverage;
847     };
848
849     BatchTracker fBatch;
850     const GrIndexBuffer* fIndexBuffer;
851     SkSTArray<1, Geometry, true> fGeoData;
852 };
853
854
855 void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
856                                             GrPipelineBuilder* pipelineBuilder,
857                                             GrColor color,
858                                             const SkMatrix& viewMatrix,
859                                             const SkRect& devOutside,
860                                             const SkRect& devOutsideAssist,
861                                             const SkRect& devInside,
862                                             bool miterStroke) {
863     GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
864     if (!indexBuffer) {
865         SkDebugf("Failed to create index buffer!\n");
866         return;
867     }
868
869     AAStrokeRectBatch::Geometry geometry;
870     geometry.fColor = color;
871     geometry.fDevOutside = devOutside;
872     geometry.fDevOutsideAssist = devOutsideAssist;
873     geometry.fDevInside = devInside;
874     geometry.fMiterStroke = miterStroke;
875
876     SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix, indexBuffer));
877     target->drawBatch(pipelineBuilder, batch);
878 }
879
880 void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
881                                          GrPipelineBuilder* pipelineBuilder,
882                                          GrColor color,
883                                          const SkMatrix& viewMatrix,
884                                          const SkRect rects[2]) {
885     SkASSERT(viewMatrix.rectStaysRect());
886     SkASSERT(!rects[1].isEmpty());
887
888     SkRect devOutside, devOutsideAssist, devInside;
889     viewMatrix.mapRect(&devOutside, rects[0]);
890     // can't call mapRect for devInside since it calls sort
891     viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
892
893     if (devInside.isEmpty()) {
894         this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutside);
895         return;
896     }
897
898     this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
899                                devOutsideAssist, devInside, true);
900 }