blob: 7f61840d73cb39541c6cdf98152f758ba6d6b86e [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
28static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
joshualitt2dd1ae02014-12-03 06:24:10 -080029 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
bsalomonc30aaa02014-08-13 07:15:29 -070030 if (drawState->canTweakAlphaForCoverage()) {
joshualitt2dd1ae02014-12-03 06:24:10 -080031 drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
32 SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
33 sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
bsalomonc30aaa02014-08-13 07:15:29 -070034 return kUseColor_CoverageAttribType;
35 } else {
joshualitt2dd1ae02014-12-03 06:24:10 -080036 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
37 drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
38 SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
39 sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
bsalomonc30aaa02014-08-13 07:15:29 -070040 return kUseCoverage_CoverageAttribType;
41 }
42}
43
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000044static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000045 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000046 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
47 r.fRight - dx, r.fBottom - dy, stride);
48}
49
robertphillips@google.comf6747b02012-06-12 00:32:28 +000050void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000051 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000052 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
53 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000054}
55
robertphillips@google.com6d067302012-12-18 21:47:47 +000056static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000057 0, 1, 5, 5, 4, 0,
58 1, 2, 6, 6, 5, 1,
59 2, 3, 7, 7, 6, 2,
60 3, 0, 4, 4, 7, 3,
61 4, 5, 6, 6, 7, 4,
62};
63
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000064static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000065static const int kVertsPerAAFillRect = 8;
66static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000067
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000068static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000069 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
70 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
71 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
72 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
73
74 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
75 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
76 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
77 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
78
79 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
80 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
81 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
82 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
83};
84
joshualitt5ead6da2014-10-22 16:00:29 -070085static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
86static const int kVertsPerMiterStrokeRect = 16;
87static const int kNumMiterStrokeRectsInIndexBuffer = 256;
88
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000089/**
90 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
91 * from the first index. The index layout:
92 * outer AA line: 0~3, 4~7
93 * outer edge: 8~11, 12~15
94 * inner edge: 16~19
95 * inner AA line: 20~23
96 * Following comes a bevel-stroke rect and its indices:
97 *
98 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +000099 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000100 * * ______________________________ *
101 * * / 12 15 \ *
102 * * / \ *
103 * 0 * |8 16_____________________19 11 | * 3
104 * * | | | | *
105 * * | | **************** | | *
106 * * | | * 20 23 * | | *
107 * * | | * * | | *
108 * * | | * 21 22 * | | *
109 * * | | **************** | | *
110 * * | |____________________| | *
111 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000112 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000113 * * \13 __________________________14/ *
114 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000115 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000116 * 5 6
117 */
118static const uint16_t gBevelStrokeAARectIdx[] = {
119 // Draw outer AA, from outer AA line to outer edge, shift is 0.
120 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
121 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
122 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
123 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
124 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
125 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
126 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
127 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
128
129 // Draw the stroke, from outer edge to inner edge, shift is 8.
130 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
131 1 + 8, 5 + 8, 9 + 8,
132 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
133 6 + 8, 2 + 8, 10 + 8,
134 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
135 3 + 8, 7 + 8, 11 + 8,
136 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
137 4 + 8, 0 + 8, 8 + 8,
138
139 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
140 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
141 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
142 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
143 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
144};
145
joshualitt5ead6da2014-10-22 16:00:29 -0700146static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
147static const int kVertsPerBevelStrokeRect = 24;
148static const int kNumBevelStrokeRectsInIndexBuffer = 256;
149
joshualittb44293e2014-10-28 08:12:18 -0700150static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000151 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
152 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000153}
154
joshualittb44293e2014-10-28 08:12:18 -0700155GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000156 if (miterStroke) {
157 if (NULL == fAAMiterStrokeRectIndexBuffer) {
158 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700159 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
160 kIndicesPerMiterStrokeRect,
161 kNumMiterStrokeRectsInIndexBuffer,
162 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000163 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000164 return fAAMiterStrokeRectIndexBuffer;
165 } else {
166 if (NULL == fAABevelStrokeRectIndexBuffer) {
167 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700168 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
169 kIndicesPerBevelStrokeRect,
170 kNumBevelStrokeRectsInIndexBuffer,
171 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000172 }
173 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000174 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000175}
176
joshualittb44293e2014-10-28 08:12:18 -0700177void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800178 GrDrawState* drawState,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000179 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000180 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700181 const SkRect& devRect) {
joshualitt5478d422014-11-14 16:00:38 -0800182 GrDrawState::AutoRestoreEffects are(drawState);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000183
bsalomon9c0822a2014-08-11 11:07:48 -0700184 GrColor color = drawState->getColor();
185
bsalomonc30aaa02014-08-13 07:15:29 -0700186 CoverageAttribType covAttribType = set_rect_attribs(drawState);
187 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700188 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
189 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000190
joshualitt2dd1ae02014-12-03 06:24:10 -0800191 size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
192 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000193 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700194 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000195 return;
196 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000197
joshualitt5ead6da2014-10-22 16:00:29 -0700198 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700199 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
200 kIndicesPerAAFillRect,
201 kNumAAFillRectsInIndexBuffer,
202 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700203 }
204 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000205 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700206 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000207 return;
208 }
209
210 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
211
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000212 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700213 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000214
robertphillips@google.com908aed82013-05-28 13:16:20 +0000215 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
216 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
217
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000218 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000219 // Temporarily #if'ed out. We don't want to pass in the devRect but
220 // right now it is computed in GrContext::apply_aa_to_rect and we don't
221 // want to throw away the work
222#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000223 SkRect devRect;
224 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000225#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000226
egdaniel7b3d5ee2014-08-28 05:41:14 -0700227 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
228 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000229 } else {
230 // compute transformed (1, 0) and (0, 1) vectors
231 SkVector vec[2] = {
232 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
233 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
234 };
235
236 vec[0].normalize();
237 vec[0].scale(SK_ScalarHalf);
238 vec[1].normalize();
239 vec[1].scale(SK_ScalarHalf);
240
robertphillips@google.com91b71162013-05-10 14:09:54 +0000241 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000242 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700243 rect.fRight, rect.fBottom, vstride);
244 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000245
robertphillips@google.com91b71162013-05-10 14:09:54 +0000246 // Now create the inset points and then outset the original
247 // rotated points
248
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000249 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700250 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
251 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
252 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000253 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700254 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
255 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
256 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000257 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700258 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
259 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
260 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000261 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700262 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
263 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
264 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000265 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000266
bsalomon9c0822a2014-08-11 11:07:48 -0700267 // 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 +0000268 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000269 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700270 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700271 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800272 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700273 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700274 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700275 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000276 }
277
robertphillips@google.com908aed82013-05-28 13:16:20 +0000278 int scale;
279 if (inset < SK_ScalarHalf) {
280 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
281 SkASSERT(scale >= 0 && scale <= 255);
282 } else {
283 scale = 0xff;
284 }
285
egdaniel7b3d5ee2014-08-28 05:41:14 -0700286 verts += 4 * vstride;
egdaniele27065a2014-11-06 08:00:48 -0800287
288 float innerCoverage = GrNormalizeByteToFloat(scale);
289 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
290
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000291 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700292 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700293 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800294 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700295 } else {
egdaniele27065a2014-11-06 08:00:48 -0800296 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700297 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000298 }
299
300 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800301 target->drawIndexedInstances(drawState,
302 kTriangles_GrPrimitiveType,
303 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000304 kVertsPerAAFillRect,
305 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000306 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000307}
308
joshualittb44293e2014-10-28 08:12:18 -0700309void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800310 GrDrawState* drawState,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000311 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000312 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000313 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700314 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000315 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700316 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000317 if (width > 0) {
318 devStrokeSize.set(width, width);
319 combinedMatrix.mapVectors(&devStrokeSize, 1);
320 devStrokeSize.setAbs(devStrokeSize);
321 } else {
322 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
323 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000324
robertphillips@google.com18136d12013-05-10 11:05:58 +0000325 const SkScalar dx = devStrokeSize.fX;
326 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000327 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
328 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000329
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000330 // Temporarily #if'ed out. We don't want to pass in the devRect but
331 // right now it is computed in GrContext::apply_aa_to_rect and we don't
332 // want to throw away the work
333#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000334 SkRect devRect;
335 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000336#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000337
bsalomon@google.com81712882012-11-01 17:12:34 +0000338 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000339 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000340 SkScalar w = devRect.width() - dx;
341 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000342 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000343 }
344
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000345 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000346 devOutside.outset(rx, ry);
347
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000348 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700349 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000350 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700351 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
352 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000353 miterStroke = false;
354 }
355
356 if (spare <= 0 && miterStroke) {
joshualitt9853cce2014-11-17 14:22:48 -0800357 this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000358 return;
359 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000360
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000361 SkRect devInside(devRect);
362 devInside.inset(rx, ry);
363
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000364 SkRect devOutsideAssist(devRect);
365
366 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
367 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000368 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000369 if (!miterStroke) {
370 devOutside.inset(0, ry);
371 devOutsideAssist.outset(0, ry);
372 }
373
joshualitt9853cce2014-11-17 14:22:48 -0800374 this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside,
375 miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000376}
377
joshualittb44293e2014-10-28 08:12:18 -0700378void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800379 GrDrawState* drawState,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000380 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000381 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000382 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000383 bool miterStroke) {
joshualitt5478d422014-11-14 16:00:38 -0800384 GrDrawState::AutoRestoreEffects are(drawState);
bsalomonc30aaa02014-08-13 07:15:29 -0700385 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700386
387 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700388 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700389 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
390 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000391
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000392 int innerVertexNum = 4;
393 int outerVertexNum = miterStroke ? 4 : 8;
394 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
395
joshualitt2dd1ae02014-12-03 06:24:10 -0800396 size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
397 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000398 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700399 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000400 return;
401 }
joshualittb44293e2014-10-28 08:12:18 -0700402 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000403 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700404 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000405 return;
406 }
407
408 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
409
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000410 // We create vertices for four nested rectangles. There are two ramps from 0 to full
411 // coverage, one on the exterior of the stroke and the other on the interior.
412 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000413 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700414 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
415 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
416 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000417
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000418#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000419 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700420 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000421 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
422 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
423 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000424 if (miterStroke) {
425 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
426 } else {
427 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
428 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000429 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000430#else
431 SkScalar inset = SK_ScalarHalf;
432#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000433
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000434 if (miterStroke) {
435 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700436 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000437 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700438 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
439 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000440 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700441 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000442 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700443 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
444 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000445 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700446 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
447 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000448 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700449 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
450 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000451 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700452 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000453 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700454 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000455 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000456
bsalomon9c0822a2014-08-11 11:07:48 -0700457 // 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 +0000458 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000459 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000460 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700461 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700462 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800463 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700464 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700465 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700466 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000467 }
468
bsalomon9c0822a2014-08-11 11:07:48 -0700469 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000470 int scale;
471 if (inset < SK_ScalarHalf) {
472 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
473 SkASSERT(scale >= 0 && scale <= 255);
474 } else {
475 scale = 0xff;
476 }
477
egdaniele27065a2014-11-06 08:00:48 -0800478 float innerCoverage = GrNormalizeByteToFloat(scale);
479 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700480
egdaniele27065a2014-11-06 08:00:48 -0800481 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000482 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700483 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700484 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800485 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700486 } else {
egdaniele27065a2014-11-06 08:00:48 -0800487 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700488 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000489 }
490
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000491 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700492 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000493 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700494 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700495 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
496 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700497 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700498 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700499 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000500 }
501
502 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800503 target->drawIndexedInstances(drawState,
504 kTriangles_GrPrimitiveType,
505 1,
506 totalVertexNum,
507 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700508 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000509}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000510
joshualittb44293e2014-10-28 08:12:18 -0700511void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800512 GrDrawState* drawState,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000513 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700514 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000515 SkASSERT(combinedMatrix.rectStaysRect());
516 SkASSERT(!rects[1].isEmpty());
517
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000518 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000519 combinedMatrix.mapRect(&devOutside, rects[0]);
520 // can't call mapRect for devInside since it calls sort
521 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
522
523 if (devInside.isEmpty()) {
joshualitt9853cce2014-11-17 14:22:48 -0800524 this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000525 return;
526 }
527
joshualitt9853cce2014-11-17 14:22:48 -0800528 this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000529}