blob: 6866b79aef886e32e2789d75bcd0579172d1883a [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"
joshualittd5a7db42015-01-27 15:39:06 -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
joshualittd5a7db42015-01-27 15:39:06 -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;
112 if (!this->viewMatrix().invert(&localMatrix)) {
113 SkDebugf("Cannot invert\n");
114 return;
115 }
116
117 const GrGeometryProcessor* gp = create_fill_rect_gp(canTweakAlphaForCoverage,
118 localMatrix);
119
120 batchTarget->initDraw(gp, pipeline);
121 gp->unref();
122
123 // TODO this is hacky, but the only way we have to initialize the GP is to use the
124 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
125 // everywhere we can remove this nastiness
126 GrPipelineInfo init;
127 init.fColorIgnored = fBatch.fColorIgnored;
128 init.fOverrideColor = GrColor_ILLEGAL;
129 init.fCoverageIgnored = fBatch.fCoverageIgnored;
130 init.fUsesLocalCoords = this->usesLocalCoords();
131 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
132
133 size_t vertexStride = gp->getVertexStride();
134
135 SkASSERT(canTweakAlphaForCoverage ?
136 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
137 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
138
139 int instanceCount = fGeoData.count();
140 int vertexCount = kVertsPerAAFillRect * instanceCount;
141
142 const GrVertexBuffer* vertexBuffer;
143 int firstVertex;
144
145 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
146 vertexCount,
147 &vertexBuffer,
148 &firstVertex);
149
150 for (int i = 0; i < instanceCount; i++) {
151 const Geometry& args = fGeoData[i];
152 this->generateAAFillRectGeometry(vertices,
153 i * kVertsPerAAFillRect * vertexStride,
154 vertexStride,
155 args.fColor,
156 args.fViewMatrix,
157 args.fRect,
158 args.fDevRect,
159 canTweakAlphaForCoverage);
160 }
161
162 GrDrawTarget::DrawInfo drawInfo;
163 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
164 drawInfo.setStartVertex(0);
165 drawInfo.setStartIndex(0);
166 drawInfo.setVerticesPerInstance(kVertsPerAAFillRect);
167 drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect);
168 drawInfo.adjustStartVertex(firstVertex);
169 drawInfo.setVertexBuffer(vertexBuffer);
170 drawInfo.setIndexBuffer(fIndexBuffer);
171
172 int maxInstancesPerDraw = kNumAAFillRectsInIndexBuffer;
173
174 while (instanceCount) {
175 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
176 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
177 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
178
179 batchTarget->draw(drawInfo);
180
181 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
182 instanceCount -= drawInfo.instanceCount();
183 }
184 }
185
186 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
187
188private:
189 AAFillRectBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
190 : fIndexBuffer(indexBuffer) {
191 this->initClassID<AAFillRectBatch>();
192 fGeoData.push_back(geometry);
193 }
194
195 GrColor color() const { return fBatch.fColor; }
196 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
197 bool canTweakAlphaForCoverage() const { return fBatchOpt.fCanTweakAlphaForCoverage; }
198 bool colorIgnored() const { return fBatch.fColorIgnored; }
199 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
200
201 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
202 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
203 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
204 return false;
205 }
206
207 if (this->colorIgnored() != that->colorIgnored()) {
208 return false;
209 }
210
211 if (this->usesLocalCoords() != that->usesLocalCoords()) {
212 return false;
213 }
214
215 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
216 // local coords then we won't be able to batch. We could actually upload the viewmatrix
217 // using vertex attributes in these cases, but haven't investigated that
218 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
219 return false;
220 }
221
222 if (this->color() != that->color()) {
223 fBatch.fColor = GrColor_ILLEGAL;
224 }
225 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
226 return true;
227 }
228
229 void generateAAFillRectGeometry(void* vertices,
230 uint32_t offset,
231 uint32_t vertexStride,
232 GrColor color,
233 const SkMatrix& viewMatrix,
234 const SkRect& rect,
235 const SkRect& devRect,
236 bool tweakAlphaForCoverage) const {
237 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
238
239 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
240 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
241
242 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
243 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
244
245 if (viewMatrix.rectStaysRect()) {
246 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
247 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
248 } else {
249 // compute transformed (1, 0) and (0, 1) vectors
250 SkVector vec[2] = {
251 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
252 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
253 };
254
255 vec[0].normalize();
256 vec[0].scale(SK_ScalarHalf);
257 vec[1].normalize();
258 vec[1].scale(SK_ScalarHalf);
259
260 // create the rotated rect
261 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
262 rect.fRight, rect.fBottom, vertexStride);
263 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
264
265 // Now create the inset points and then outset the original
266 // rotated points
267
268 // TL
269 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
270 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
271 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
272 // BL
273 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
274 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
275 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
276 // BR
277 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
278 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
279 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
280 // TR
281 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
282 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
283 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
284 }
285
286 // Make verts point to vertex color and then set all the color and coverage vertex attrs
287 // values.
288 verts += sizeof(SkPoint);
289 for (int i = 0; i < 4; ++i) {
290 if (tweakAlphaForCoverage) {
291 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
292 } else {
293 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
294 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
295 }
296 }
297
298 int scale;
299 if (inset < SK_ScalarHalf) {
300 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
301 SkASSERT(scale >= 0 && scale <= 255);
302 } else {
303 scale = 0xff;
304 }
305
306 verts += 4 * vertexStride;
307
308 float innerCoverage = GrNormalizeByteToFloat(scale);
309 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
310
311 for (int i = 0; i < 4; ++i) {
312 if (tweakAlphaForCoverage) {
313 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
314 } else {
315 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
316 *reinterpret_cast<float*>(verts + i * vertexStride +
317 sizeof(GrColor)) = innerCoverage;
318 }
319 }
320 }
321
322 struct BatchTracker {
323 GrColor fColor;
324 bool fUsesLocalCoords;
325 bool fColorIgnored;
326 bool fCoverageIgnored;
327 };
328
329 GrBatchOpt fBatchOpt;
330 BatchTracker fBatch;
331 const GrIndexBuffer* fIndexBuffer;
332 SkSTArray<1, Geometry, true> fGeoData;
333};
334
335namespace {
336// Should the coverage be multiplied into the color attrib or use a separate attrib.
337enum CoverageAttribType {
338 kUseColor_CoverageAttribType,
339 kUseCoverage_CoverageAttribType,
340};
341}
342
343void GrAARectRenderer::reset() {
344 SkSafeSetNull(fAAFillRectIndexBuffer);
345 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
346 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
347}
348
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000349static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000350 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
351 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
352 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
353 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
354
355 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
356 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
357 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
358 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
359
360 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
361 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
362 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
363 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
364};
365
joshualitt5ead6da2014-10-22 16:00:29 -0700366static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
367static const int kVertsPerMiterStrokeRect = 16;
368static const int kNumMiterStrokeRectsInIndexBuffer = 256;
369
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000370/**
371 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
372 * from the first index. The index layout:
373 * outer AA line: 0~3, 4~7
374 * outer edge: 8~11, 12~15
375 * inner edge: 16~19
376 * inner AA line: 20~23
377 * Following comes a bevel-stroke rect and its indices:
378 *
379 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000380 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000381 * * ______________________________ *
382 * * / 12 15 \ *
383 * * / \ *
384 * 0 * |8 16_____________________19 11 | * 3
385 * * | | | | *
386 * * | | **************** | | *
387 * * | | * 20 23 * | | *
388 * * | | * * | | *
389 * * | | * 21 22 * | | *
390 * * | | **************** | | *
391 * * | |____________________| | *
392 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000393 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000394 * * \13 __________________________14/ *
395 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000396 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000397 * 5 6
398 */
399static const uint16_t gBevelStrokeAARectIdx[] = {
400 // Draw outer AA, from outer AA line to outer edge, shift is 0.
401 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
402 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
403 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
404 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
405 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
406 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
407 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
408 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
409
410 // Draw the stroke, from outer edge to inner edge, shift is 8.
411 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
412 1 + 8, 5 + 8, 9 + 8,
413 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
414 6 + 8, 2 + 8, 10 + 8,
415 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
416 3 + 8, 7 + 8, 11 + 8,
417 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
418 4 + 8, 0 + 8, 8 + 8,
419
420 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
421 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
422 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
423 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
424 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
425};
426
joshualitt5ead6da2014-10-22 16:00:29 -0700427static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
428static const int kVertsPerBevelStrokeRect = 24;
429static const int kNumBevelStrokeRectsInIndexBuffer = 256;
430
joshualittb44293e2014-10-28 08:12:18 -0700431static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000432 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
433 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434}
435
joshualittb44293e2014-10-28 08:12:18 -0700436GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000437 if (miterStroke) {
438 if (NULL == fAAMiterStrokeRectIndexBuffer) {
439 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700440 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
441 kIndicesPerMiterStrokeRect,
442 kNumMiterStrokeRectsInIndexBuffer,
443 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000444 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000445 return fAAMiterStrokeRectIndexBuffer;
446 } else {
447 if (NULL == fAABevelStrokeRectIndexBuffer) {
448 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700449 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
450 kIndicesPerBevelStrokeRect,
451 kNumBevelStrokeRectsInIndexBuffer,
452 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000453 }
454 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000455 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000456}
457
joshualittb44293e2014-10-28 08:12:18 -0700458void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800459 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800460 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800461 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000462 const SkRect& rect,
bsalomon9c0822a2014-08-11 11:07:48 -0700463 const SkRect& devRect) {
joshualitt5ead6da2014-10-22 16:00:29 -0700464 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700465 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
466 kIndicesPerAAFillRect,
467 kNumAAFillRectsInIndexBuffer,
468 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700469 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000470
joshualittd5a7db42015-01-27 15:39:06 -0800471 AAFillRectBatch::Geometry geometry;
472 geometry.fRect = rect;
473 geometry.fViewMatrix = viewMatrix;
474 geometry.fDevRect = devRect;
475 geometry.fColor = color;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000476
joshualittd5a7db42015-01-27 15:39:06 -0800477 SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
478 target->drawBatch(pipelineBuilder, batch, &devRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000479}
480
joshualittb44293e2014-10-28 08:12:18 -0700481void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800482 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800483 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800484 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000485 const SkRect& rect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000486 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700487 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000488 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700489 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000490 if (width > 0) {
491 devStrokeSize.set(width, width);
joshualitt8059eb92014-12-29 15:10:07 -0800492 viewMatrix.mapVectors(&devStrokeSize, 1);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000493 devStrokeSize.setAbs(devStrokeSize);
494 } else {
495 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
496 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000497
robertphillips@google.com18136d12013-05-10 11:05:58 +0000498 const SkScalar dx = devStrokeSize.fX;
499 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000500 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
501 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000502
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000503 // Temporarily #if'ed out. We don't want to pass in the devRect but
504 // right now it is computed in GrContext::apply_aa_to_rect and we don't
505 // want to throw away the work
506#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000507 SkRect devRect;
508 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000509#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000510
bsalomon@google.com81712882012-11-01 17:12:34 +0000511 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000512 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000513 SkScalar w = devRect.width() - dx;
514 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000515 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000516 }
517
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000518 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000519 devOutside.outset(rx, ry);
520
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000521 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700522 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000523 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700524 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
525 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000526 miterStroke = false;
527 }
528
529 if (spare <= 0 && miterStroke) {
egdaniel8dd688b2015-01-22 10:16:09 -0800530 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800531 devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000532 return;
533 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000534
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000535 SkRect devInside(devRect);
536 devInside.inset(rx, ry);
537
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000538 SkRect devOutsideAssist(devRect);
539
540 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
541 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000542 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000543 if (!miterStroke) {
544 devOutside.inset(0, ry);
545 devOutsideAssist.outset(0, ry);
546 }
547
joshualittd5a7db42015-01-27 15:39:06 -0800548 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
549 devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000550}
551
joshualittd5a7db42015-01-27 15:39:06 -0800552static const GrGeometryProcessor* create_rect_gp(const GrPipelineBuilder& pipelneBuilder,
553 GrColor color,
554 CoverageAttribType* type,
555 const SkMatrix& localMatrix) {
556 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
557 const GrGeometryProcessor* gp;
558 if (pipelneBuilder.canTweakAlphaForCoverage()) {
559 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localMatrix);
560 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
561 *type = kUseColor_CoverageAttribType;
562 } else {
563 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
564 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localMatrix,
565 GrColorIsOpaque(color));
566 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
567 *type = kUseCoverage_CoverageAttribType;
568 }
569 return gp;
570}
571
572
joshualittb44293e2014-10-28 08:12:18 -0700573void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800574 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800575 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800576 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000577 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000578 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000579 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000580 bool miterStroke) {
joshualitt8059eb92014-12-29 15:10:07 -0800581 SkMatrix localMatrix;
582 if (!viewMatrix.invert(&localMatrix)) {
583 SkDebugf("Cannot invert\n");
584 return;
585 }
586
joshualitt56995b52014-12-11 15:44:02 -0800587 CoverageAttribType type;
egdaniel8dd688b2015-01-22 10:16:09 -0800588 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*pipelineBuilder, color, &type,
joshualittd27f73e2014-12-29 07:43:36 -0800589 localMatrix));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000590
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000591 int innerVertexNum = 4;
592 int outerVertexNum = miterStroke ? 4 : 8;
593 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
594
joshualitt56995b52014-12-11 15:44:02 -0800595 size_t vstride = gp->getVertexStride();
joshualitt2dd1ae02014-12-03 06:24:10 -0800596 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000597 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700598 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000599 return;
600 }
joshualittb44293e2014-10-28 08:12:18 -0700601 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000602 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700603 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000604 return;
605 }
606
607 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
608
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000609 // We create vertices for four nested rectangles. There are two ramps from 0 to full
610 // coverage, one on the exterior of the stroke and the other on the interior.
611 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000612 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700613 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
614 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
615 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000616
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000617#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000618 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700619 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000620 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
621 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
622 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000623 if (miterStroke) {
624 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
625 } else {
626 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
627 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000628 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000629#else
630 SkScalar inset = SK_ScalarHalf;
631#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000632
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000633 if (miterStroke) {
634 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700635 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000636 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700637 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
638 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000639 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700640 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000641 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700642 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
643 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000644 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700645 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
646 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000647 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700648 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
649 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000650 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700651 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000652 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700653 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000654 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000655
bsalomon9c0822a2014-08-11 11:07:48 -0700656 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000657 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000658 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000659 for (int i = 0; i < outerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800660 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700661 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800662 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700663 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700664 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700665 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000666 }
667
bsalomon9c0822a2014-08-11 11:07:48 -0700668 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000669 int scale;
670 if (inset < SK_ScalarHalf) {
671 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
672 SkASSERT(scale >= 0 && scale <= 255);
673 } else {
674 scale = 0xff;
675 }
676
egdaniele27065a2014-11-06 08:00:48 -0800677 float innerCoverage = GrNormalizeByteToFloat(scale);
678 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700679
egdaniele27065a2014-11-06 08:00:48 -0800680 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000681 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800682 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700683 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800684 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700685 } else {
egdaniele27065a2014-11-06 08:00:48 -0800686 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700687 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000688 }
689
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000690 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700691 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000692 for (int i = 0; i < innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800693 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700694 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
695 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700696 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700697 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700698 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000699 }
700
701 target->setIndexSourceToBuffer(indexBuffer);
egdaniel8dd688b2015-01-22 10:16:09 -0800702 target->drawIndexedInstances(pipelineBuilder,
joshualitt56995b52014-12-11 15:44:02 -0800703 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800704 kTriangles_GrPrimitiveType,
705 1,
706 totalVertexNum,
707 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700708 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000709}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000710
joshualittb44293e2014-10-28 08:12:18 -0700711void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800712 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800713 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800714 const SkMatrix& viewMatrix,
715 const SkRect rects[2]) {
716 SkASSERT(viewMatrix.rectStaysRect());
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000717 SkASSERT(!rects[1].isEmpty());
718
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000719 SkRect devOutside, devOutsideAssist, devInside;
joshualitt8059eb92014-12-29 15:10:07 -0800720 viewMatrix.mapRect(&devOutside, rects[0]);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000721 // can't call mapRect for devInside since it calls sort
joshualitt8059eb92014-12-29 15:10:07 -0800722 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000723
724 if (devInside.isEmpty()) {
egdaniel8dd688b2015-01-22 10:16:09 -0800725 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800726 devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000727 return;
728 }
729
egdaniel8dd688b2015-01-22 10:16:09 -0800730 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
731 devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000732}