blob: 0ffdd4d9f92d5f8694ab3dcbd52c734d164a9b1d [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"
joshualitt5478d422014-11-14 16:00:38 -08009#include "GrDefaultGeoProcFactory.h"
10#include "GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000011#include "GrGpu.h"
egdaniel605dd0f2014-11-12 08:35:25 -080012#include "GrInvariantOutput.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000013#include "SkColorPriv.h"
joshualitt5478d422014-11-14 16:00:38 -080014#include "gl/GrGLProcessor.h"
15#include "gl/GrGLGeometryProcessor.h"
16#include "gl/builders/GrGLProgramBuilder.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000017
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000018///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000019
robertphillips@google.comf6747b02012-06-12 00:32:28 +000020namespace {
bsalomonc30aaa02014-08-13 07:15:29 -070021// Should the coverage be multiplied into the color attrib or use a separate attrib.
22enum CoverageAttribType {
23 kUseColor_CoverageAttribType,
24 kUseCoverage_CoverageAttribType,
25};
26}
27
egdaniel8dd688b2015-01-22 10:16:09 -080028static const GrGeometryProcessor* create_rect_gp(const GrPipelineBuilder& pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -080029 GrColor color,
joshualittd27f73e2014-12-29 07:43:36 -080030 CoverageAttribType* type,
31 const SkMatrix& localMatrix) {
joshualitt2dd1ae02014-12-03 06:24:10 -080032 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
joshualitt56995b52014-12-11 15:44:02 -080033 const GrGeometryProcessor* gp;
egdaniel8dd688b2015-01-22 10:16:09 -080034 if (pipelineBuilder.canTweakAlphaForCoverage()) {
joshualitt8059eb92014-12-29 15:10:07 -080035 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localMatrix);
joshualitt56995b52014-12-11 15:44:02 -080036 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
37 *type = kUseColor_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070038 } else {
joshualitt2dd1ae02014-12-03 06:24:10 -080039 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
joshualitt8059eb92014-12-29 15:10:07 -080040 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localMatrix,
41 GrColorIsOpaque(color));
joshualitt56995b52014-12-11 15:44:02 -080042 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
43 *type = kUseCoverage_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070044 }
joshualitt56995b52014-12-11 15:44:02 -080045 return gp;
bsalomonc30aaa02014-08-13 07:15:29 -070046}
47
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000048static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000049 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000050 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
51 r.fRight - dx, r.fBottom - dy, stride);
52}
53
robertphillips@google.comf6747b02012-06-12 00:32:28 +000054void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000055 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000056 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
57 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000058}
59
robertphillips@google.com6d067302012-12-18 21:47:47 +000060static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000061 0, 1, 5, 5, 4, 0,
62 1, 2, 6, 6, 5, 1,
63 2, 3, 7, 7, 6, 2,
64 3, 0, 4, 4, 7, 3,
65 4, 5, 6, 6, 7, 4,
66};
67
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000068static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000069static const int kVertsPerAAFillRect = 8;
70static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000071
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000072static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000073 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
74 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
75 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
76 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
77
78 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
79 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
80 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
81 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
82
83 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
84 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
85 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
86 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
87};
88
joshualitt5ead6da2014-10-22 16:00:29 -070089static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
90static const int kVertsPerMiterStrokeRect = 16;
91static const int kNumMiterStrokeRectsInIndexBuffer = 256;
92
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000093/**
94 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
95 * from the first index. The index layout:
96 * outer AA line: 0~3, 4~7
97 * outer edge: 8~11, 12~15
98 * inner edge: 16~19
99 * inner AA line: 20~23
100 * Following comes a bevel-stroke rect and its indices:
101 *
102 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000103 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000104 * * ______________________________ *
105 * * / 12 15 \ *
106 * * / \ *
107 * 0 * |8 16_____________________19 11 | * 3
108 * * | | | | *
109 * * | | **************** | | *
110 * * | | * 20 23 * | | *
111 * * | | * * | | *
112 * * | | * 21 22 * | | *
113 * * | | **************** | | *
114 * * | |____________________| | *
115 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000116 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000117 * * \13 __________________________14/ *
118 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000119 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000120 * 5 6
121 */
122static const uint16_t gBevelStrokeAARectIdx[] = {
123 // Draw outer AA, from outer AA line to outer edge, shift is 0.
124 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
125 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
126 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
127 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
128 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
129 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
130 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
131 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
132
133 // Draw the stroke, from outer edge to inner edge, shift is 8.
134 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
135 1 + 8, 5 + 8, 9 + 8,
136 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
137 6 + 8, 2 + 8, 10 + 8,
138 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
139 3 + 8, 7 + 8, 11 + 8,
140 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
141 4 + 8, 0 + 8, 8 + 8,
142
143 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
144 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
145 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
146 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
147 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
148};
149
joshualitt5ead6da2014-10-22 16:00:29 -0700150static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
151static const int kVertsPerBevelStrokeRect = 24;
152static const int kNumBevelStrokeRectsInIndexBuffer = 256;
153
joshualittb44293e2014-10-28 08:12:18 -0700154static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000155 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
156 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000157}
158
joshualittb44293e2014-10-28 08:12:18 -0700159GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000160 if (miterStroke) {
161 if (NULL == fAAMiterStrokeRectIndexBuffer) {
162 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700163 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
164 kIndicesPerMiterStrokeRect,
165 kNumMiterStrokeRectsInIndexBuffer,
166 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000167 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000168 return fAAMiterStrokeRectIndexBuffer;
169 } else {
170 if (NULL == fAABevelStrokeRectIndexBuffer) {
171 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700172 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
173 kIndicesPerBevelStrokeRect,
174 kNumBevelStrokeRectsInIndexBuffer,
175 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000176 }
177 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000178 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000179}
180
joshualittb44293e2014-10-28 08:12:18 -0700181void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800182 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800183 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800184 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000185 const SkRect& rect,
bsalomon9c0822a2014-08-11 11:07:48 -0700186 const SkRect& devRect) {
egdaniel8dd688b2015-01-22 10:16:09 -0800187 GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000188
joshualitt8059eb92014-12-29 15:10:07 -0800189 SkMatrix localMatrix;
190 if (!viewMatrix.invert(&localMatrix)) {
191 SkDebugf("Cannot invert\n");
192 return;
193 }
194
joshualitt56995b52014-12-11 15:44:02 -0800195 CoverageAttribType type;
egdaniel8dd688b2015-01-22 10:16:09 -0800196 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*pipelineBuilder, color, &type,
joshualittd27f73e2014-12-29 07:43:36 -0800197 localMatrix));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000198
joshualitt56995b52014-12-11 15:44:02 -0800199 size_t vertexStride = gp->getVertexStride();
200 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000201 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700202 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000203 return;
204 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000205
joshualitt5ead6da2014-10-22 16:00:29 -0700206 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700207 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
208 kIndicesPerAAFillRect,
209 kNumAAFillRectsInIndexBuffer,
210 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700211 }
212 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000213 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700214 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000215 return;
216 }
217
218 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
219
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000220 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
joshualitt56995b52014-12-11 15:44:02 -0800221 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000222
robertphillips@google.com908aed82013-05-28 13:16:20 +0000223 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
224 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
225
joshualitt8059eb92014-12-29 15:10:07 -0800226 if (viewMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000227 // Temporarily #if'ed out. We don't want to pass in the devRect but
228 // right now it is computed in GrContext::apply_aa_to_rect and we don't
229 // want to throw away the work
230#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000231 SkRect devRect;
232 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000233#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000234
joshualitt56995b52014-12-11 15:44:02 -0800235 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
236 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000237 } else {
238 // compute transformed (1, 0) and (0, 1) vectors
239 SkVector vec[2] = {
joshualitt8059eb92014-12-29 15:10:07 -0800240 { viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY] },
241 { viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY] }
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000242 };
243
244 vec[0].normalize();
245 vec[0].scale(SK_ScalarHalf);
246 vec[1].normalize();
247 vec[1].scale(SK_ScalarHalf);
248
robertphillips@google.com91b71162013-05-10 14:09:54 +0000249 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000250 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
joshualitt56995b52014-12-11 15:44:02 -0800251 rect.fRight, rect.fBottom, vertexStride);
joshualitt8059eb92014-12-29 15:10:07 -0800252 viewMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000253
robertphillips@google.com91b71162013-05-10 14:09:54 +0000254 // Now create the inset points and then outset the original
255 // rotated points
256
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000257 // TL
joshualitt56995b52014-12-11 15:44:02 -0800258 *((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];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000261 // BL
joshualitt56995b52014-12-11 15:44:02 -0800262 *((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];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000265 // BR
joshualitt56995b52014-12-11 15:44:02 -0800266 *((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];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000269 // TR
joshualitt56995b52014-12-11 15:44:02 -0800270 *((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];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000273 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000274
bsalomon9c0822a2014-08-11 11:07:48 -0700275 // Make verts point to vertex color and then set all the color and coverage vertex attrs values.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000276 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000277 for (int i = 0; i < 4; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800278 if (kUseCoverage_CoverageAttribType == type) {
279 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
280 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700281 } else {
joshualitt56995b52014-12-11 15:44:02 -0800282 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700283 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000284 }
285
robertphillips@google.com908aed82013-05-28 13:16:20 +0000286 int scale;
287 if (inset < SK_ScalarHalf) {
288 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
289 SkASSERT(scale >= 0 && scale <= 255);
290 } else {
291 scale = 0xff;
292 }
293
joshualitt56995b52014-12-11 15:44:02 -0800294 verts += 4 * vertexStride;
egdaniele27065a2014-11-06 08:00:48 -0800295
296 float innerCoverage = GrNormalizeByteToFloat(scale);
297 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
298
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000299 for (int i = 0; i < 4; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800300 if (kUseCoverage_CoverageAttribType == type) {
301 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
302 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700303 } else {
joshualitt56995b52014-12-11 15:44:02 -0800304 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700305 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000306 }
307
308 target->setIndexSourceToBuffer(indexBuffer);
egdaniel8dd688b2015-01-22 10:16:09 -0800309 target->drawIndexedInstances(pipelineBuilder,
joshualitt56995b52014-12-11 15:44:02 -0800310 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800311 kTriangles_GrPrimitiveType,
312 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000313 kVertsPerAAFillRect,
314 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000315 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000316}
317
joshualittb44293e2014-10-28 08:12:18 -0700318void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800319 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800320 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800321 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000322 const SkRect& rect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000323 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700324 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000325 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700326 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000327 if (width > 0) {
328 devStrokeSize.set(width, width);
joshualitt8059eb92014-12-29 15:10:07 -0800329 viewMatrix.mapVectors(&devStrokeSize, 1);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000330 devStrokeSize.setAbs(devStrokeSize);
331 } else {
332 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
333 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000334
robertphillips@google.com18136d12013-05-10 11:05:58 +0000335 const SkScalar dx = devStrokeSize.fX;
336 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000337 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
338 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000339
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000340 // Temporarily #if'ed out. We don't want to pass in the devRect but
341 // right now it is computed in GrContext::apply_aa_to_rect and we don't
342 // want to throw away the work
343#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000344 SkRect devRect;
345 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000346#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000347
bsalomon@google.com81712882012-11-01 17:12:34 +0000348 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000349 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000350 SkScalar w = devRect.width() - dx;
351 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000352 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000353 }
354
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000355 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000356 devOutside.outset(rx, ry);
357
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000358 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700359 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000360 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700361 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
362 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000363 miterStroke = false;
364 }
365
366 if (spare <= 0 && miterStroke) {
egdaniel8dd688b2015-01-22 10:16:09 -0800367 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800368 devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000369 return;
370 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000371
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000372 SkRect devInside(devRect);
373 devInside.inset(rx, ry);
374
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000375 SkRect devOutsideAssist(devRect);
376
377 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
378 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000379 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000380 if (!miterStroke) {
381 devOutside.inset(0, ry);
382 devOutsideAssist.outset(0, ry);
383 }
384
egdaniel8dd688b2015-01-22 10:16:09 -0800385 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside, devOutsideAssist,
joshualittd27f73e2014-12-29 07:43:36 -0800386 devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000387}
388
joshualittb44293e2014-10-28 08:12:18 -0700389void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800390 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800391 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800392 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000393 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000394 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000395 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000396 bool miterStroke) {
egdaniel8dd688b2015-01-22 10:16:09 -0800397 GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder);
bsalomon9c0822a2014-08-11 11:07:48 -0700398
joshualitt8059eb92014-12-29 15:10:07 -0800399 SkMatrix localMatrix;
400 if (!viewMatrix.invert(&localMatrix)) {
401 SkDebugf("Cannot invert\n");
402 return;
403 }
404
joshualitt56995b52014-12-11 15:44:02 -0800405 CoverageAttribType type;
egdaniel8dd688b2015-01-22 10:16:09 -0800406 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*pipelineBuilder, color, &type,
joshualittd27f73e2014-12-29 07:43:36 -0800407 localMatrix));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000408
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000409 int innerVertexNum = 4;
410 int outerVertexNum = miterStroke ? 4 : 8;
411 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
412
joshualitt56995b52014-12-11 15:44:02 -0800413 size_t vstride = gp->getVertexStride();
joshualitt2dd1ae02014-12-03 06:24:10 -0800414 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000415 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700416 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000417 return;
418 }
joshualittb44293e2014-10-28 08:12:18 -0700419 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000420 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700421 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000422 return;
423 }
424
425 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
426
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000427 // We create vertices for four nested rectangles. There are two ramps from 0 to full
428 // coverage, one on the exterior of the stroke and the other on the interior.
429 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000430 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700431 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
432 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
433 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000435#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000436 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700437 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000438 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
439 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
440 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000441 if (miterStroke) {
442 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
443 } else {
444 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
445 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000446 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000447#else
448 SkScalar inset = SK_ScalarHalf;
449#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000450
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000451 if (miterStroke) {
452 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700453 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000454 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700455 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
456 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000457 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700458 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000459 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700460 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
461 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000462 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700463 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
464 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000465 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700466 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
467 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000468 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700469 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000470 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700471 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000472 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000473
bsalomon9c0822a2014-08-11 11:07:48 -0700474 // 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 +0000475 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000476 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000477 for (int i = 0; i < outerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800478 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700479 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800480 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700481 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700482 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700483 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000484 }
485
bsalomon9c0822a2014-08-11 11:07:48 -0700486 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000487 int scale;
488 if (inset < SK_ScalarHalf) {
489 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
490 SkASSERT(scale >= 0 && scale <= 255);
491 } else {
492 scale = 0xff;
493 }
494
egdaniele27065a2014-11-06 08:00:48 -0800495 float innerCoverage = GrNormalizeByteToFloat(scale);
496 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700497
egdaniele27065a2014-11-06 08:00:48 -0800498 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000499 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800500 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700501 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800502 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700503 } else {
egdaniele27065a2014-11-06 08:00:48 -0800504 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700505 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000506 }
507
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000508 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700509 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000510 for (int i = 0; i < innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800511 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700512 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
513 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700514 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700515 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700516 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000517 }
518
519 target->setIndexSourceToBuffer(indexBuffer);
egdaniel8dd688b2015-01-22 10:16:09 -0800520 target->drawIndexedInstances(pipelineBuilder,
joshualitt56995b52014-12-11 15:44:02 -0800521 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800522 kTriangles_GrPrimitiveType,
523 1,
524 totalVertexNum,
525 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700526 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000527}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000528
joshualittb44293e2014-10-28 08:12:18 -0700529void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800530 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800531 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800532 const SkMatrix& viewMatrix,
533 const SkRect rects[2]) {
534 SkASSERT(viewMatrix.rectStaysRect());
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000535 SkASSERT(!rects[1].isEmpty());
536
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000537 SkRect devOutside, devOutsideAssist, devInside;
joshualitt8059eb92014-12-29 15:10:07 -0800538 viewMatrix.mapRect(&devOutside, rects[0]);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000539 // can't call mapRect for devInside since it calls sort
joshualitt8059eb92014-12-29 15:10:07 -0800540 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000541
542 if (devInside.isEmpty()) {
egdaniel8dd688b2015-01-22 10:16:09 -0800543 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
joshualittd27f73e2014-12-29 07:43:36 -0800544 devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000545 return;
546 }
547
egdaniel8dd688b2015-01-22 10:16:09 -0800548 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOutside,
549 devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000550}