blob: 7e86c0b49d10ea022bbb38df53aea0acb2dff6bf [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAARectRenderer.h"
joshualitt4d8da812015-01-28 12:53:54 -08009#include "GrBatch.h"
10#include "GrBatchTarget.h"
11#include "GrBufferAllocPool.h"
joshualitt5478d422014-11-14 16:00:38 -080012#include "GrDefaultGeoProcFactory.h"
13#include "GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000014#include "GrGpu.h"
egdaniel605dd0f2014-11-12 08:35:25 -080015#include "GrInvariantOutput.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000016#include "SkColorPriv.h"
joshualitt5478d422014-11-14 16:00:38 -080017#include "gl/GrGLProcessor.h"
18#include "gl/GrGLGeometryProcessor.h"
19#include "gl/builders/GrGLProgramBuilder.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000020
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000021///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000022
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000023static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000024 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000025 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
26 r.fRight - dx, r.fBottom - dy, stride);
27}
28
robertphillips@google.com6d067302012-12-18 21:47:47 +000029static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000030 0, 1, 5, 5, 4, 0,
31 1, 2, 6, 6, 5, 1,
32 2, 3, 7, 7, 6, 2,
33 3, 0, 4, 4, 7, 3,
34 4, 5, 6, 6, 7, 4,
35};
36
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000037static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000038static const int kVertsPerAAFillRect = 8;
39static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000040
joshualitt4d8da812015-01-28 12:53:54 -080041static const GrGeometryProcessor* create_fill_rect_gp(bool tweakAlphaForCoverage,
42 const SkMatrix& localMatrix) {
43 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
44 const GrGeometryProcessor* gp;
45 if (tweakAlphaForCoverage) {
46 gp = GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE, SkMatrix::I(), localMatrix,
47 false, 0xff);
48 } else {
49 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
50 gp = GrDefaultGeoProcFactory::Create(flags, GrColor_WHITE, SkMatrix::I(), localMatrix,
51 false, 0xff);
52 }
53 return gp;
54}
55
56class AAFillRectBatch : public GrBatch {
57public:
58 struct Geometry {
59 GrColor fColor;
60 SkMatrix fViewMatrix;
61 SkRect fRect;
62 SkRect fDevRect;
63 };
64
65 static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* indexBuffer) {
66 return SkNEW_ARGS(AAFillRectBatch, (geometry, indexBuffer));
67 }
68
69 const char* name() const SK_OVERRIDE { return "AAFillRectBatch"; }
70
71 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
72 // When this is called on a batch, there is only one geometry bundle
joshualittdb0f9512015-02-13 12:50:09 -080073 out->setKnownFourComponents(fGeoData[0].fColor);
joshualitt4d8da812015-01-28 12:53:54 -080074 }
75
76 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE {
joshualittdb0f9512015-02-13 12:50:09 -080077 out->setUnknownSingleComponent();
joshualitt4d8da812015-01-28 12:53:54 -080078 }
79
80 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
81 // Handle any color overrides
82 if (init.fColorIgnored) {
83 fGeoData[0].fColor = GrColor_ILLEGAL;
84 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
85 fGeoData[0].fColor = init.fOverrideColor;
86 }
87
88 // setup batch properties
89 fBatch.fColorIgnored = init.fColorIgnored;
90 fBatch.fColor = fGeoData[0].fColor;
91 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
92 fBatch.fCoverageIgnored = init.fCoverageIgnored;
joshualittdb0f9512015-02-13 12:50:09 -080093 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage;
joshualitt4d8da812015-01-28 12:53:54 -080094 }
95
96 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) SK_OVERRIDE {
97 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage();
98
99 SkMatrix localMatrix;
joshualitt84b13df2015-02-12 15:03:49 -0800100 if (!this->viewMatrix().invert(&localMatrix)) {
joshualitt4d8da812015-01-28 12:53:54 -0800101 SkDebugf("Cannot invert\n");
102 return;
103 }
104
joshualitt84b13df2015-02-12 15:03:49 -0800105 const GrGeometryProcessor* gp = create_fill_rect_gp(canTweakAlphaForCoverage,
106 localMatrix);
joshualitt4d8da812015-01-28 12:53:54 -0800107
108 batchTarget->initDraw(gp, pipeline);
joshualitt84b13df2015-02-12 15:03:49 -0800109 gp->unref();
joshualitt4d8da812015-01-28 12:53:54 -0800110
111 // TODO this is hacky, but the only way we have to initialize the GP is to use the
112 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
113 // everywhere we can remove this nastiness
114 GrPipelineInfo init;
115 init.fColorIgnored = fBatch.fColorIgnored;
116 init.fOverrideColor = GrColor_ILLEGAL;
117 init.fCoverageIgnored = fBatch.fCoverageIgnored;
118 init.fUsesLocalCoords = this->usesLocalCoords();
119 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
120
121 size_t vertexStride = gp->getVertexStride();
122
123 SkASSERT(canTweakAlphaForCoverage ?
124 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAttr) :
125 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
126
127 int instanceCount = fGeoData.count();
128 int vertexCount = kVertsPerAAFillRect * instanceCount;
129
130 const GrVertexBuffer* vertexBuffer;
131 int firstVertex;
132
joshualitt84b13df2015-02-12 15:03:49 -0800133 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
joshualitt4d8da812015-01-28 12:53:54 -0800134 vertexCount,
135 &vertexBuffer,
136 &firstVertex);
137
138 for (int i = 0; i < instanceCount; i++) {
139 const Geometry& args = fGeoData[i];
140 this->generateAAFillRectGeometry(vertices,
joshualitt84b13df2015-02-12 15:03:49 -0800141 i * kVertsPerAAFillRect * vertexStride,
142 vertexStride,
143 args.fColor,
144 args.fViewMatrix,
145 args.fRect,
146 args.fDevRect,
147 canTweakAlphaForCoverage);
joshualitt4d8da812015-01-28 12:53:54 -0800148 }
149
150 GrDrawTarget::DrawInfo drawInfo;
151 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
152 drawInfo.setStartVertex(0);
153 drawInfo.setStartIndex(0);
154 drawInfo.setVerticesPerInstance(kVertsPerAAFillRect);
155 drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect);
156 drawInfo.adjustStartVertex(firstVertex);
157 drawInfo.setVertexBuffer(vertexBuffer);
158 drawInfo.setIndexBuffer(fIndexBuffer);
159
160 int maxInstancesPerDraw = kNumAAFillRectsInIndexBuffer;
161
162 while (instanceCount) {
163 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw));
164 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.verticesPerInstance());
165 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPerInstance());
166
167 batchTarget->draw(drawInfo);
168
169 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCount());
170 instanceCount -= drawInfo.instanceCount();
171 }
172 }
173
174 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
175
176private:
177 AAFillRectBatch(const Geometry& geometry, const GrIndexBuffer* indexBuffer)
178 : fIndexBuffer(indexBuffer) {
179 this->initClassID<AAFillRectBatch>();
180 fGeoData.push_back(geometry);
181 }
182
183 GrColor color() const { return fBatch.fColor; }
184 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
joshualittdb0f9512015-02-13 12:50:09 -0800185 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCoverage; }
joshualitt4d8da812015-01-28 12:53:54 -0800186 bool colorIgnored() const { return fBatch.fColorIgnored; }
187 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
188
189 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
190 AAFillRectBatch* that = t->cast<AAFillRectBatch>();
joshualitt84b13df2015-02-12 15:03:49 -0800191
192 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
joshualitt4d8da812015-01-28 12:53:54 -0800193 // We apply the viewmatrix to the rect points on the cpu. However, if the pipeline uses
194 // local coords then we won't be able to batch. We could actually upload the viewmatrix
195 // using vertex attributes in these cases, but haven't investigated that
196 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
197 return false;
198 }
199
200 if (this->color() != that->color()) {
201 fBatch.fColor = GrColor_ILLEGAL;
202 }
joshualittdb0f9512015-02-13 12:50:09 -0800203
204 // In the event of two batches, one who can tweak, one who cannot, we just fall back to
205 // not tweaking
206 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()) {
207 fBatch.fCanTweakAlphaForCoverage = false;
208 }
209
joshualitt4d8da812015-01-28 12:53:54 -0800210 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
211 return true;
212 }
213
214 void generateAAFillRectGeometry(void* vertices,
bsalomon81aca542015-01-29 07:13:20 -0800215 size_t offset,
216 size_t vertexStride,
joshualitt4d8da812015-01-28 12:53:54 -0800217 GrColor color,
218 const SkMatrix& viewMatrix,
219 const SkRect& rect,
220 const SkRect& devRect,
221 bool tweakAlphaForCoverage) const {
222 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset;
223
224 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
225 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
226
227 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
228 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
229
230 if (viewMatrix.rectStaysRect()) {
231 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
232 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
233 } else {
234 // compute transformed (1, 0) and (0, 1) vectors
235 SkVector vec[2] = {
236 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
237 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
238 };
239
240 vec[0].normalize();
241 vec[0].scale(SK_ScalarHalf);
242 vec[1].normalize();
243 vec[1].scale(SK_ScalarHalf);
244
245 // create the rotated rect
246 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
247 rect.fRight, rect.fBottom, vertexStride);
248 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
249
250 // Now create the inset points and then outset the original
251 // rotated points
252
253 // TL
254 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
255 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
256 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
257 // BL
258 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
259 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
260 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
261 // BR
262 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
263 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
264 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
265 // TR
266 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
267 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
268 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
269 }
270
271 // Make verts point to vertex color and then set all the color and coverage vertex attrs
272 // values.
273 verts += sizeof(SkPoint);
274 for (int i = 0; i < 4; ++i) {
275 if (tweakAlphaForCoverage) {
276 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
277 } else {
278 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
279 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
280 }
281 }
282
283 int scale;
284 if (inset < SK_ScalarHalf) {
285 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
286 SkASSERT(scale >= 0 && scale <= 255);
287 } else {
288 scale = 0xff;
289 }
290
291 verts += 4 * vertexStride;
292
293 float innerCoverage = GrNormalizeByteToFloat(scale);
294 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
295
296 for (int i = 0; i < 4; ++i) {
297 if (tweakAlphaForCoverage) {
298 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
299 } else {
300 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
301 *reinterpret_cast<float*>(verts + i * vertexStride +
302 sizeof(GrColor)) = innerCoverage;
303 }
304 }
305 }
306
307 struct BatchTracker {
308 GrColor fColor;
309 bool fUsesLocalCoords;
310 bool fColorIgnored;
311 bool fCoverageIgnored;
joshualittdb0f9512015-02-13 12:50:09 -0800312 bool fCanTweakAlphaForCoverage;
joshualitt4d8da812015-01-28 12:53:54 -0800313 };
314
joshualitt4d8da812015-01-28 12:53:54 -0800315 BatchTracker fBatch;
316 const GrIndexBuffer* fIndexBuffer;
317 SkSTArray<1, Geometry, true> fGeoData;
318};
319
320namespace {
321// Should the coverage be multiplied into the color attrib or use a separate attrib.
322enum CoverageAttribType {
323 kUseColor_CoverageAttribType,
324 kUseCoverage_CoverageAttribType,
325};
326}
327
328void GrAARectRenderer::reset() {
329 SkSafeSetNull(fAAFillRectIndexBuffer);
330 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
331 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
332}
333
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000334static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000335 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
336 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
337 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
338 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
339
340 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
341 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
342 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
343 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
344
345 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
346 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
347 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
348 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
349};
350
joshualitt5ead6da2014-10-22 16:00:29 -0700351static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
352static const int kVertsPerMiterStrokeRect = 16;
353static const int kNumMiterStrokeRectsInIndexBuffer = 256;
354
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000355/**
356 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
357 * from the first index. The index layout:
358 * outer AA line: 0~3, 4~7
359 * outer edge: 8~11, 12~15
360 * inner edge: 16~19
361 * inner AA line: 20~23
362 * Following comes a bevel-stroke rect and its indices:
363 *
364 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000365 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000366 * * ______________________________ *
367 * * / 12 15 \ *
368 * * / \ *
369 * 0 * |8 16_____________________19 11 | * 3
370 * * | | | | *
371 * * | | **************** | | *
372 * * | | * 20 23 * | | *
373 * * | | * * | | *
374 * * | | * 21 22 * | | *
375 * * | | **************** | | *
376 * * | |____________________| | *
377 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000378 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000379 * * \13 __________________________14/ *
380 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000381 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000382 * 5 6
383 */
384static const uint16_t gBevelStrokeAARectIdx[] = {
385 // Draw outer AA, from outer AA line to outer edge, shift is 0.
386 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
387 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
388 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
389 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
390 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
391 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
392 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
393 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
394
395 // Draw the stroke, from outer edge to inner edge, shift is 8.
396 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
397 1 + 8, 5 + 8, 9 + 8,
398 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
399 6 + 8, 2 + 8, 10 + 8,
400 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
401 3 + 8, 7 + 8, 11 + 8,
402 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
403 4 + 8, 0 + 8, 8 + 8,
404
405 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
406 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
407 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
408 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
409 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
410};
411
joshualitt5ead6da2014-10-22 16:00:29 -0700412static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
413static const int kVertsPerBevelStrokeRect = 24;
414static const int kNumBevelStrokeRectsInIndexBuffer = 256;
415
joshualittb44293e2014-10-28 08:12:18 -0700416static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000417 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
418 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000419}
420
joshualittb44293e2014-10-28 08:12:18 -0700421GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000422 if (miterStroke) {
423 if (NULL == fAAMiterStrokeRectIndexBuffer) {
424 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700425 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
426 kIndicesPerMiterStrokeRect,
427 kNumMiterStrokeRectsInIndexBuffer,
428 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000429 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000430 return fAAMiterStrokeRectIndexBuffer;
431 } else {
432 if (NULL == fAABevelStrokeRectIndexBuffer) {
433 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700434 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
435 kIndicesPerBevelStrokeRect,
436 kNumBevelStrokeRectsInIndexBuffer,
437 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000438 }
439 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000440 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000441}
442
joshualittb44293e2014-10-28 08:12:18 -0700443void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800444 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800445 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800446 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000447 const SkRect& rect,
bsalomon9c0822a2014-08-11 11:07:48 -0700448 const SkRect& devRect) {
joshualitt5ead6da2014-10-22 16:00:29 -0700449 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700450 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
451 kIndicesPerAAFillRect,
452 kNumAAFillRectsInIndexBuffer,
453 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700454 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000455
joshualitt4d8da812015-01-28 12:53:54 -0800456 AAFillRectBatch::Geometry geometry;
457 geometry.fRect = rect;
458 geometry.fViewMatrix = viewMatrix;
459 geometry.fDevRect = devRect;
460 geometry.fColor = color;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000461
joshualitt4d8da812015-01-28 12:53:54 -0800462 SkAutoTUnref<GrBatch> batch(AAFillRectBatch::Create(geometry, fAAFillRectIndexBuffer));
463 target->drawBatch(pipelineBuilder, batch, &devRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000464}
465
joshualittb44293e2014-10-28 08:12:18 -0700466void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800467 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800468 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800469 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000470 const SkRect& rect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000471 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700472 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000473 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700474 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000475 if (width > 0) {
476 devStrokeSize.set(width, width);
joshualitt8059eb92014-12-29 15:10:07 -0800477 viewMatrix.mapVectors(&devStrokeSize, 1);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000478 devStrokeSize.setAbs(devStrokeSize);
479 } else {
480 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
481 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000482
robertphillips@google.com18136d12013-05-10 11:05:58 +0000483 const SkScalar dx = devStrokeSize.fX;
484 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000485 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
486 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000487
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000488 // Temporarily #if'ed out. We don't want to pass in the devRect but
489 // right now it is computed in GrContext::apply_aa_to_rect and we don't
490 // want to throw away the work
491#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000492 SkRect devRect;
493 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000494#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000495
bsalomon@google.com81712882012-11-01 17:12:34 +0000496 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000497 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000498 SkScalar w = devRect.width() - dx;
499 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000500 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000501 }
502
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000503 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000504 devOutside.outset(rx, ry);
505
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000506 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700507 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000508 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700509 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
510 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000511 miterStroke = false;
512 }
513
514 if (spare <= 0 && miterStroke) {
egdaniel8dd688b2015-01-22 10:16:09 -0800515 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800516 devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000517 return;
518 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000519
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000520 SkRect devInside(devRect);
521 devInside.inset(rx, ry);
522
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000523 SkRect devOutsideAssist(devRect);
524
525 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
526 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000527 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000528 if (!miterStroke) {
529 devOutside.inset(0, ry);
530 devOutsideAssist.outset(0, ry);
531 }
532
joshualitt4d8da812015-01-28 12:53:54 -0800533 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
534 devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000535}
536
joshualitt84b13df2015-02-12 15:03:49 -0800537static const GrGeometryProcessor* create_rect_gp(const GrPipelineBuilder& pipelneBuilder,
538 GrColor color,
539 CoverageAttribType* type,
540 const SkMatrix& localMatrix) {
541 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
542 const GrGeometryProcessor* gp;
543 if (pipelneBuilder.canTweakAlphaForCoverage()) {
544 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localMatrix);
545 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
546 *type = kUseColor_CoverageAttribType;
547 } else {
548 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
549 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localMatrix,
550 GrColorIsOpaque(color));
551 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
552 *type = kUseCoverage_CoverageAttribType;
joshualitt4d8da812015-01-28 12:53:54 -0800553 }
joshualitt84b13df2015-02-12 15:03:49 -0800554 return gp;
555}
joshualitt4d8da812015-01-28 12:53:54 -0800556
557
joshualittb44293e2014-10-28 08:12:18 -0700558void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800559 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800560 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800561 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000562 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000563 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000564 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000565 bool miterStroke) {
joshualitt84b13df2015-02-12 15:03:49 -0800566 SkMatrix localMatrix;
567 if (!viewMatrix.invert(&localMatrix)) {
568 SkDebugf("Cannot invert\n");
569 return;
570 }
571
572 CoverageAttribType type;
573 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*pipelineBuilder, color, &type,
574 localMatrix));
575
576 int innerVertexNum = 4;
577 int outerVertexNum = miterStroke ? 4 : 8;
578 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
579
580 size_t vstride = gp->getVertexStride();
581 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
582 if (!geo.succeeded()) {
583 SkDebugf("Failed to get space for vertices!\n");
584 return;
585 }
joshualittb44293e2014-10-28 08:12:18 -0700586 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000587 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700588 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000589 return;
590 }
591
joshualitt84b13df2015-02-12 15:03:49 -0800592 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000593
joshualitt84b13df2015-02-12 15:03:49 -0800594 // We create vertices for four nested rectangles. There are two ramps from 0 to full
595 // coverage, one on the exterior of the stroke and the other on the interior.
596 // The following pointers refer to the four rects, from outermost to innermost.
597 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
598 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
599 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
600 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
601
602#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
603 // TODO: this only really works if the X & Y margins are the same all around
604 // the rect (or if they are all >= 1.0).
605 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
606 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
607 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
608 if (miterStroke) {
609 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
610 } else {
611 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
612 }
613 SkASSERT(inset >= 0);
614#else
615 SkScalar inset = SK_ScalarHalf;
616#endif
617
618 if (miterStroke) {
619 // outermost
620 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
621 // inner two
622 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
623 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
624 // innermost
625 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
626 } else {
627 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
628 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
629 // outermost
630 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
631 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
632 // outer one of the inner two
633 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
634 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
635 // inner one of the inner two
636 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
637 // innermost
638 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
639 }
640
641 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
642 // The outermost rect has 0 coverage
643 verts += sizeof(SkPoint);
644 for (int i = 0; i < outerVertexNum; ++i) {
645 if (kUseCoverage_CoverageAttribType == type) {
646 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
647 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
648 } else {
649 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
650 }
651 }
652
653 // scale is the coverage for the the inner two rects.
654 int scale;
655 if (inset < SK_ScalarHalf) {
656 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
657 SkASSERT(scale >= 0 && scale <= 255);
658 } else {
659 scale = 0xff;
660 }
661
662 float innerCoverage = GrNormalizeByteToFloat(scale);
663 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
664
665 verts += outerVertexNum * vstride;
666 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
667 if (kUseCoverage_CoverageAttribType == type) {
668 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
669 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
670 } else {
671 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
672 }
673 }
674
675 // The innermost rect has 0 coverage
676 verts += (outerVertexNum + innerVertexNum) * vstride;
677 for (int i = 0; i < innerVertexNum; ++i) {
678 if (kUseCoverage_CoverageAttribType == type) {
679 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
680 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
681 } else {
682 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
683 }
684 }
685
686 target->setIndexSourceToBuffer(indexBuffer);
687 target->drawIndexedInstances(pipelineBuilder,
688 gp,
689 kTriangles_GrPrimitiveType,
690 1,
691 totalVertexNum,
692 aa_stroke_rect_index_count(miterStroke));
693 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000694}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000695
joshualittb44293e2014-10-28 08:12:18 -0700696void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800697 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800698 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800699 const SkMatrix& viewMatrix,
700 const SkRect rects[2]) {
701 SkASSERT(viewMatrix.rectStaysRect());
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000702 SkASSERT(!rects[1].isEmpty());
703
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000704 SkRect devOutside, devOutsideAssist, devInside;
joshualitt8059eb92014-12-29 15:10:07 -0800705 viewMatrix.mapRect(&devOutside, rects[0]);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000706 // can't call mapRect for devInside since it calls sort
joshualitt8059eb92014-12-29 15:10:07 -0800707 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000708
709 if (devInside.isEmpty()) {
egdaniel8dd688b2015-01-22 10:16:09 -0800710 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800711 devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000712 return;
713 }
714
egdaniel8dd688b2015-01-22 10:16:09 -0800715 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
716 devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000717}