blob: 3f0e1b0117181c5d56df9d4a6243e0cf06e2dff6 [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
joshualitt56995b52014-12-11 15:44:02 -080028static const GrGeometryProcessor* create_rect_gp(const GrDrawState& drawState, GrColor color,
joshualittd27f73e2014-12-29 07:43:36 -080029 CoverageAttribType* type,
30 const SkMatrix& localMatrix) {
joshualitt2dd1ae02014-12-03 06:24:10 -080031 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
joshualitt56995b52014-12-11 15:44:02 -080032 const GrGeometryProcessor* gp;
33 if (drawState.canTweakAlphaForCoverage()) {
joshualittd27f73e2014-12-29 07:43:36 -080034 gp = GrDefaultGeoProcFactory::Create(color, flags, localMatrix);
joshualitt56995b52014-12-11 15:44:02 -080035 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
36 *type = kUseColor_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070037 } else {
joshualitt2dd1ae02014-12-03 06:24:10 -080038 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
joshualittd27f73e2014-12-29 07:43:36 -080039 gp = GrDefaultGeoProcFactory::Create(color, flags, GrColorIsOpaque(color), 0xff,
40 localMatrix);
joshualitt56995b52014-12-11 15:44:02 -080041 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
42 *type = kUseCoverage_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070043 }
joshualitt56995b52014-12-11 15:44:02 -080044 return gp;
bsalomonc30aaa02014-08-13 07:15:29 -070045}
46
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000047static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000048 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000049 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
50 r.fRight - dx, r.fBottom - dy, stride);
51}
52
robertphillips@google.comf6747b02012-06-12 00:32:28 +000053void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000054 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000055 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
56 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000057}
58
robertphillips@google.com6d067302012-12-18 21:47:47 +000059static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000060 0, 1, 5, 5, 4, 0,
61 1, 2, 6, 6, 5, 1,
62 2, 3, 7, 7, 6, 2,
63 3, 0, 4, 4, 7, 3,
64 4, 5, 6, 6, 7, 4,
65};
66
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000067static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000068static const int kVertsPerAAFillRect = 8;
69static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000070
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000071static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000072 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
73 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
74 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
75 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
76
77 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
78 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
79 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
80 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
81
82 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
83 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
84 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
85 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
86};
87
joshualitt5ead6da2014-10-22 16:00:29 -070088static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
89static const int kVertsPerMiterStrokeRect = 16;
90static const int kNumMiterStrokeRectsInIndexBuffer = 256;
91
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000092/**
93 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
94 * from the first index. The index layout:
95 * outer AA line: 0~3, 4~7
96 * outer edge: 8~11, 12~15
97 * inner edge: 16~19
98 * inner AA line: 20~23
99 * Following comes a bevel-stroke rect and its indices:
100 *
101 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000102 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000103 * * ______________________________ *
104 * * / 12 15 \ *
105 * * / \ *
106 * 0 * |8 16_____________________19 11 | * 3
107 * * | | | | *
108 * * | | **************** | | *
109 * * | | * 20 23 * | | *
110 * * | | * * | | *
111 * * | | * 21 22 * | | *
112 * * | | **************** | | *
113 * * | |____________________| | *
114 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000115 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000116 * * \13 __________________________14/ *
117 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000118 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000119 * 5 6
120 */
121static const uint16_t gBevelStrokeAARectIdx[] = {
122 // Draw outer AA, from outer AA line to outer edge, shift is 0.
123 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
124 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
125 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
126 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
127 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
128 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
129 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
130 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
131
132 // Draw the stroke, from outer edge to inner edge, shift is 8.
133 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
134 1 + 8, 5 + 8, 9 + 8,
135 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
136 6 + 8, 2 + 8, 10 + 8,
137 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
138 3 + 8, 7 + 8, 11 + 8,
139 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
140 4 + 8, 0 + 8, 8 + 8,
141
142 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
143 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
144 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
145 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
146 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
147};
148
joshualitt5ead6da2014-10-22 16:00:29 -0700149static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
150static const int kVertsPerBevelStrokeRect = 24;
151static const int kNumBevelStrokeRectsInIndexBuffer = 256;
152
joshualittb44293e2014-10-28 08:12:18 -0700153static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000154 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
155 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000156}
157
joshualittb44293e2014-10-28 08:12:18 -0700158GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000159 if (miterStroke) {
160 if (NULL == fAAMiterStrokeRectIndexBuffer) {
161 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700162 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
163 kIndicesPerMiterStrokeRect,
164 kNumMiterStrokeRectsInIndexBuffer,
165 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000166 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000167 return fAAMiterStrokeRectIndexBuffer;
168 } else {
169 if (NULL == fAABevelStrokeRectIndexBuffer) {
170 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700171 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
172 kIndicesPerBevelStrokeRect,
173 kNumBevelStrokeRectsInIndexBuffer,
174 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000175 }
176 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000177 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000178}
179
joshualittb44293e2014-10-28 08:12:18 -0700180void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800181 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800182 GrColor color,
joshualittd27f73e2014-12-29 07:43:36 -0800183 const SkMatrix& localMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000184 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000185 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700186 const SkRect& devRect) {
joshualitt5478d422014-11-14 16:00:38 -0800187 GrDrawState::AutoRestoreEffects are(drawState);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000188
joshualitt56995b52014-12-11 15:44:02 -0800189 CoverageAttribType type;
joshualittd27f73e2014-12-29 07:43:36 -0800190 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type,
191 localMatrix));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000192
joshualitt56995b52014-12-11 15:44:02 -0800193 size_t vertexStride = gp->getVertexStride();
194 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000195 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700196 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000197 return;
198 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000199
joshualitt5ead6da2014-10-22 16:00:29 -0700200 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700201 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
202 kIndicesPerAAFillRect,
203 kNumAAFillRectsInIndexBuffer,
204 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700205 }
206 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000207 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700208 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000209 return;
210 }
211
212 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
213
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000214 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
joshualitt56995b52014-12-11 15:44:02 -0800215 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000216
robertphillips@google.com908aed82013-05-28 13:16:20 +0000217 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
218 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
219
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000220 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000221 // Temporarily #if'ed out. We don't want to pass in the devRect but
222 // right now it is computed in GrContext::apply_aa_to_rect and we don't
223 // want to throw away the work
224#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000225 SkRect devRect;
226 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000227#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000228
joshualitt56995b52014-12-11 15:44:02 -0800229 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
230 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000231 } else {
232 // compute transformed (1, 0) and (0, 1) vectors
233 SkVector vec[2] = {
234 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
235 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
236 };
237
238 vec[0].normalize();
239 vec[0].scale(SK_ScalarHalf);
240 vec[1].normalize();
241 vec[1].scale(SK_ScalarHalf);
242
robertphillips@google.com91b71162013-05-10 14:09:54 +0000243 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000244 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
joshualitt56995b52014-12-11 15:44:02 -0800245 rect.fRight, rect.fBottom, vertexStride);
246 combinedMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000247
robertphillips@google.com91b71162013-05-10 14:09:54 +0000248 // Now create the inset points and then outset the original
249 // rotated points
250
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000251 // TL
joshualitt56995b52014-12-11 15:44:02 -0800252 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
253 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
254 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000255 // BL
joshualitt56995b52014-12-11 15:44:02 -0800256 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
257 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
258 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000259 // BR
joshualitt56995b52014-12-11 15:44:02 -0800260 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
261 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
262 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000263 // TR
joshualitt56995b52014-12-11 15:44:02 -0800264 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
265 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
266 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000267 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268
bsalomon9c0822a2014-08-11 11:07:48 -0700269 // 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 +0000270 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000271 for (int i = 0; i < 4; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800272 if (kUseCoverage_CoverageAttribType == type) {
273 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
274 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700275 } else {
joshualitt56995b52014-12-11 15:44:02 -0800276 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700277 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000278 }
279
robertphillips@google.com908aed82013-05-28 13:16:20 +0000280 int scale;
281 if (inset < SK_ScalarHalf) {
282 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
283 SkASSERT(scale >= 0 && scale <= 255);
284 } else {
285 scale = 0xff;
286 }
287
joshualitt56995b52014-12-11 15:44:02 -0800288 verts += 4 * vertexStride;
egdaniele27065a2014-11-06 08:00:48 -0800289
290 float innerCoverage = GrNormalizeByteToFloat(scale);
291 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
292
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000293 for (int i = 0; i < 4; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800294 if (kUseCoverage_CoverageAttribType == type) {
295 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
296 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700297 } else {
joshualitt56995b52014-12-11 15:44:02 -0800298 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700299 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000300 }
301
302 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800303 target->drawIndexedInstances(drawState,
joshualitt56995b52014-12-11 15:44:02 -0800304 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800305 kTriangles_GrPrimitiveType,
306 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000307 kVertsPerAAFillRect,
308 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000309 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000310}
311
joshualittb44293e2014-10-28 08:12:18 -0700312void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800313 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800314 GrColor color,
joshualittd27f73e2014-12-29 07:43:36 -0800315 const SkMatrix& localMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000316 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000317 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000318 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700319 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000320 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700321 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000322 if (width > 0) {
323 devStrokeSize.set(width, width);
324 combinedMatrix.mapVectors(&devStrokeSize, 1);
325 devStrokeSize.setAbs(devStrokeSize);
326 } else {
327 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
328 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000329
robertphillips@google.com18136d12013-05-10 11:05:58 +0000330 const SkScalar dx = devStrokeSize.fX;
331 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000332 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
333 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000334
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000335 // Temporarily #if'ed out. We don't want to pass in the devRect but
336 // right now it is computed in GrContext::apply_aa_to_rect and we don't
337 // want to throw away the work
338#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000339 SkRect devRect;
340 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000341#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000342
bsalomon@google.com81712882012-11-01 17:12:34 +0000343 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000344 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000345 SkScalar w = devRect.width() - dx;
346 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000347 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000348 }
349
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000350 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000351 devOutside.outset(rx, ry);
352
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000353 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700354 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000355 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700356 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
357 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000358 miterStroke = false;
359 }
360
361 if (spare <= 0 && miterStroke) {
joshualittd27f73e2014-12-29 07:43:36 -0800362 this->fillAARect(target, drawState, color, localMatrix, devOutside, SkMatrix::I(),
363 devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000364 return;
365 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000366
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000367 SkRect devInside(devRect);
368 devInside.inset(rx, ry);
369
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000370 SkRect devOutsideAssist(devRect);
371
372 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
373 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000374 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000375 if (!miterStroke) {
376 devOutside.inset(0, ry);
377 devOutsideAssist.outset(0, ry);
378 }
379
joshualittd27f73e2014-12-29 07:43:36 -0800380 this->geometryStrokeAARect(target, drawState, color, localMatrix, devOutside, devOutsideAssist,
381 devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000382}
383
joshualittb44293e2014-10-28 08:12:18 -0700384void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800385 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800386 GrColor color,
joshualittd27f73e2014-12-29 07:43:36 -0800387 const SkMatrix& localMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000388 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000389 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000390 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000391 bool miterStroke) {
joshualitt5478d422014-11-14 16:00:38 -0800392 GrDrawState::AutoRestoreEffects are(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700393
joshualitt56995b52014-12-11 15:44:02 -0800394 CoverageAttribType type;
joshualittd27f73e2014-12-29 07:43:36 -0800395 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type,
396 localMatrix));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000397
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000398 int innerVertexNum = 4;
399 int outerVertexNum = miterStroke ? 4 : 8;
400 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
401
joshualitt56995b52014-12-11 15:44:02 -0800402 size_t vstride = gp->getVertexStride();
joshualitt2dd1ae02014-12-03 06:24:10 -0800403 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000404 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700405 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000406 return;
407 }
joshualittb44293e2014-10-28 08:12:18 -0700408 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000409 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700410 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000411 return;
412 }
413
414 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
415
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000416 // We create vertices for four nested rectangles. There are two ramps from 0 to full
417 // coverage, one on the exterior of the stroke and the other on the interior.
418 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000419 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700420 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
421 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
422 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000423
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000424#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000425 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700426 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000427 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
428 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
429 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000430 if (miterStroke) {
431 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
432 } else {
433 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
434 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000435 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000436#else
437 SkScalar inset = SK_ScalarHalf;
438#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000439
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000440 if (miterStroke) {
441 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700442 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000443 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700444 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
445 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000446 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700447 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000448 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700449 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
450 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000451 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700452 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
453 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000454 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700455 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
456 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000457 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700458 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000459 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700460 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000461 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000462
bsalomon9c0822a2014-08-11 11:07:48 -0700463 // 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 +0000464 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000465 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000466 for (int i = 0; i < outerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800467 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700468 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800469 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700470 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700471 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700472 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000473 }
474
bsalomon9c0822a2014-08-11 11:07:48 -0700475 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000476 int scale;
477 if (inset < SK_ScalarHalf) {
478 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
479 SkASSERT(scale >= 0 && scale <= 255);
480 } else {
481 scale = 0xff;
482 }
483
egdaniele27065a2014-11-06 08:00:48 -0800484 float innerCoverage = GrNormalizeByteToFloat(scale);
485 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700486
egdaniele27065a2014-11-06 08:00:48 -0800487 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000488 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800489 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700490 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800491 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700492 } else {
egdaniele27065a2014-11-06 08:00:48 -0800493 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700494 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000495 }
496
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000497 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700498 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000499 for (int i = 0; i < 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;
502 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700503 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700504 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700505 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000506 }
507
508 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800509 target->drawIndexedInstances(drawState,
joshualitt56995b52014-12-11 15:44:02 -0800510 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800511 kTriangles_GrPrimitiveType,
512 1,
513 totalVertexNum,
514 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700515 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000516}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000517
joshualittb44293e2014-10-28 08:12:18 -0700518void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800519 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800520 GrColor color,
joshualittd27f73e2014-12-29 07:43:36 -0800521 const SkMatrix& localMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000522 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700523 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000524 SkASSERT(combinedMatrix.rectStaysRect());
525 SkASSERT(!rects[1].isEmpty());
526
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000527 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000528 combinedMatrix.mapRect(&devOutside, rects[0]);
529 // can't call mapRect for devInside since it calls sort
530 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
531
532 if (devInside.isEmpty()) {
joshualittd27f73e2014-12-29 07:43:36 -0800533 this->fillAARect(target, drawState, color, localMatrix, devOutside, SkMatrix::I(),
534 devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000535 return;
536 }
537
joshualittd27f73e2014-12-29 07:43:36 -0800538 this->geometryStrokeAARect(target, drawState, color, localMatrix, devOutside, devOutsideAssist,
539 devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000540}