blob: 0cf757502e45e326bee841db0a898b88900e9871 [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
joshualitt2e3b3e32014-12-09 13:31:14 -080028static CoverageAttribType set_rect_attribs(GrDrawState* drawState, GrColor color) {
joshualitt2dd1ae02014-12-03 06:24:10 -080029 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
bsalomonc30aaa02014-08-13 07:15:29 -070030 if (drawState->canTweakAlphaForCoverage()) {
joshualitt2e3b3e32014-12-09 13:31:14 -080031 drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
joshualitt2dd1ae02014-12-03 06:24:10 -080032 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;
joshualitt2e3b3e32014-12-09 13:31:14 -080037 drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(color, flags))->unref();
joshualitt2dd1ae02014-12-03 06:24:10 -080038 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,
joshualitt2e3b3e32014-12-09 13:31:14 -0800179 GrColor color,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000180 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000181 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700182 const SkRect& devRect) {
joshualitt5478d422014-11-14 16:00:38 -0800183 GrDrawState::AutoRestoreEffects are(drawState);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000184
joshualitt2e3b3e32014-12-09 13:31:14 -0800185 CoverageAttribType covAttribType = set_rect_attribs(drawState, color);
bsalomonc30aaa02014-08-13 07:15:29 -0700186 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700187 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
188 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000189
joshualitt2dd1ae02014-12-03 06:24:10 -0800190 size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
191 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000192 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700193 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000194 return;
195 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000196
joshualitt5ead6da2014-10-22 16:00:29 -0700197 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700198 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
199 kIndicesPerAAFillRect,
200 kNumAAFillRectsInIndexBuffer,
201 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700202 }
203 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000204 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700205 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000206 return;
207 }
208
209 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
210
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000211 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700212 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000213
robertphillips@google.com908aed82013-05-28 13:16:20 +0000214 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
215 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
216
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000217 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000218 // Temporarily #if'ed out. We don't want to pass in the devRect but
219 // right now it is computed in GrContext::apply_aa_to_rect and we don't
220 // want to throw away the work
221#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000222 SkRect devRect;
223 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000224#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000225
egdaniel7b3d5ee2014-08-28 05:41:14 -0700226 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
227 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000228 } else {
229 // compute transformed (1, 0) and (0, 1) vectors
230 SkVector vec[2] = {
231 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
232 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
233 };
234
235 vec[0].normalize();
236 vec[0].scale(SK_ScalarHalf);
237 vec[1].normalize();
238 vec[1].scale(SK_ScalarHalf);
239
robertphillips@google.com91b71162013-05-10 14:09:54 +0000240 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000241 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700242 rect.fRight, rect.fBottom, vstride);
243 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000244
robertphillips@google.com91b71162013-05-10 14:09:54 +0000245 // Now create the inset points and then outset the original
246 // rotated points
247
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000248 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700249 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
250 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
251 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000252 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700253 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
254 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
255 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000256 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700257 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
258 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
259 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000260 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700261 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
262 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
263 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000264 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000265
bsalomon9c0822a2014-08-11 11:07:48 -0700266 // 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 +0000267 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700269 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700270 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800271 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700272 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700273 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700274 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000275 }
276
robertphillips@google.com908aed82013-05-28 13:16:20 +0000277 int scale;
278 if (inset < SK_ScalarHalf) {
279 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
280 SkASSERT(scale >= 0 && scale <= 255);
281 } else {
282 scale = 0xff;
283 }
284
egdaniel7b3d5ee2014-08-28 05:41:14 -0700285 verts += 4 * vstride;
egdaniele27065a2014-11-06 08:00:48 -0800286
287 float innerCoverage = GrNormalizeByteToFloat(scale);
288 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
289
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700291 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700292 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800293 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700294 } else {
egdaniele27065a2014-11-06 08:00:48 -0800295 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700296 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000297 }
298
299 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800300 target->drawIndexedInstances(drawState,
301 kTriangles_GrPrimitiveType,
302 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000303 kVertsPerAAFillRect,
304 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000305 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000306}
307
joshualittb44293e2014-10-28 08:12:18 -0700308void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800309 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800310 GrColor color,
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) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800357 this->fillAARect(target, drawState, color, 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
joshualitt2e3b3e32014-12-09 13:31:14 -0800374 this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
joshualitt9853cce2014-11-17 14:22:48 -0800375 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,
joshualitt2e3b3e32014-12-09 13:31:14 -0800380 GrColor color,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000381 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000382 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000383 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000384 bool miterStroke) {
joshualitt5478d422014-11-14 16:00:38 -0800385 GrDrawState::AutoRestoreEffects are(drawState);
joshualitt2e3b3e32014-12-09 13:31:14 -0800386 CoverageAttribType covAttribType = set_rect_attribs(drawState, color);
bsalomon9c0822a2014-08-11 11:07:48 -0700387
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,
joshualitt2e3b3e32014-12-09 13:31:14 -0800513 GrColor color,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000514 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700515 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000516 SkASSERT(combinedMatrix.rectStaysRect());
517 SkASSERT(!rects[1].isEmpty());
518
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000519 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000520 combinedMatrix.mapRect(&devOutside, rects[0]);
521 // can't call mapRect for devInside since it calls sort
522 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
523
524 if (devInside.isEmpty()) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800525 this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000526 return;
527 }
528
joshualitt2e3b3e32014-12-09 13:31:14 -0800529 this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
530 true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000531}