blob: 23757ce8c536d552dec40a121f8e0890d78c2c98 [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
joshualittc6bc58e2014-12-10 13:48:57 -080028static const GrGeometryProcessor* create_rect_gp(const GrDrawState& drawState, GrColor color,
29 CoverageAttribType* type) {
joshualitt2dd1ae02014-12-03 06:24:10 -080030 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
joshualittc6bc58e2014-12-10 13:48:57 -080031 const GrGeometryProcessor* gp;
32 if (drawState.canTweakAlphaForCoverage()) {
33 gp = GrDefaultGeoProcFactory::Create(color, flags);
34 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
35 *type = kUseColor_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070036 } else {
joshualitt2dd1ae02014-12-03 06:24:10 -080037 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
joshualittc6bc58e2014-12-10 13:48:57 -080038 gp = GrDefaultGeoProcFactory::Create(color, flags);
39 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
40 *type = kUseCoverage_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070041 }
joshualittc6bc58e2014-12-10 13:48:57 -080042 return gp;
bsalomonc30aaa02014-08-13 07:15:29 -070043}
44
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000045static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000046 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000047 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
48 r.fRight - dx, r.fBottom - dy, stride);
49}
50
robertphillips@google.comf6747b02012-06-12 00:32:28 +000051void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000052 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000053 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
54 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000055}
56
robertphillips@google.com6d067302012-12-18 21:47:47 +000057static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000058 0, 1, 5, 5, 4, 0,
59 1, 2, 6, 6, 5, 1,
60 2, 3, 7, 7, 6, 2,
61 3, 0, 4, 4, 7, 3,
62 4, 5, 6, 6, 7, 4,
63};
64
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000065static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000066static const int kVertsPerAAFillRect = 8;
67static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000068
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000069static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000070 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
71 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
72 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
73 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
74
75 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
76 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
77 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
78 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
79
80 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
81 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
82 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
83 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
84};
85
joshualitt5ead6da2014-10-22 16:00:29 -070086static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
87static const int kVertsPerMiterStrokeRect = 16;
88static const int kNumMiterStrokeRectsInIndexBuffer = 256;
89
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000090/**
91 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
92 * from the first index. The index layout:
93 * outer AA line: 0~3, 4~7
94 * outer edge: 8~11, 12~15
95 * inner edge: 16~19
96 * inner AA line: 20~23
97 * Following comes a bevel-stroke rect and its indices:
98 *
99 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000100 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000101 * * ______________________________ *
102 * * / 12 15 \ *
103 * * / \ *
104 * 0 * |8 16_____________________19 11 | * 3
105 * * | | | | *
106 * * | | **************** | | *
107 * * | | * 20 23 * | | *
108 * * | | * * | | *
109 * * | | * 21 22 * | | *
110 * * | | **************** | | *
111 * * | |____________________| | *
112 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000113 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000114 * * \13 __________________________14/ *
115 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000116 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000117 * 5 6
118 */
119static const uint16_t gBevelStrokeAARectIdx[] = {
120 // Draw outer AA, from outer AA line to outer edge, shift is 0.
121 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
122 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
123 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
124 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
125 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
126 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
127 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
128 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
129
130 // Draw the stroke, from outer edge to inner edge, shift is 8.
131 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
132 1 + 8, 5 + 8, 9 + 8,
133 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
134 6 + 8, 2 + 8, 10 + 8,
135 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
136 3 + 8, 7 + 8, 11 + 8,
137 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
138 4 + 8, 0 + 8, 8 + 8,
139
140 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
141 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
142 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
143 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
144 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
145};
146
joshualitt5ead6da2014-10-22 16:00:29 -0700147static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
148static const int kVertsPerBevelStrokeRect = 24;
149static const int kNumBevelStrokeRectsInIndexBuffer = 256;
150
joshualittb44293e2014-10-28 08:12:18 -0700151static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000152 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
153 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000154}
155
joshualittb44293e2014-10-28 08:12:18 -0700156GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000157 if (miterStroke) {
158 if (NULL == fAAMiterStrokeRectIndexBuffer) {
159 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700160 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
161 kIndicesPerMiterStrokeRect,
162 kNumMiterStrokeRectsInIndexBuffer,
163 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000164 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000165 return fAAMiterStrokeRectIndexBuffer;
166 } else {
167 if (NULL == fAABevelStrokeRectIndexBuffer) {
168 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700169 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
170 kIndicesPerBevelStrokeRect,
171 kNumBevelStrokeRectsInIndexBuffer,
172 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000173 }
174 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000175 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000176}
177
joshualittb44293e2014-10-28 08:12:18 -0700178void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800179 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800180 GrColor color,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000181 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000182 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700183 const SkRect& devRect) {
joshualitt5478d422014-11-14 16:00:38 -0800184 GrDrawState::AutoRestoreEffects are(drawState);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000185
joshualittc6bc58e2014-12-10 13:48:57 -0800186 CoverageAttribType type;
187 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
188 if (kUseCoverage_CoverageAttribType == type && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700189 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
190 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000191
joshualittc6bc58e2014-12-10 13:48:57 -0800192 size_t vertexStride = gp->getVertexStride();
193 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000194 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700195 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000196 return;
197 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000198
joshualitt5ead6da2014-10-22 16:00:29 -0700199 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700200 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
201 kIndicesPerAAFillRect,
202 kNumAAFillRectsInIndexBuffer,
203 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700204 }
205 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000206 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700207 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000208 return;
209 }
210
211 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
212
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000213 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
joshualittc6bc58e2014-12-10 13:48:57 -0800214 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000215
robertphillips@google.com908aed82013-05-28 13:16:20 +0000216 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
217 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
218
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000219 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000220 // Temporarily #if'ed out. We don't want to pass in the devRect but
221 // right now it is computed in GrContext::apply_aa_to_rect and we don't
222 // want to throw away the work
223#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000224 SkRect devRect;
225 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000226#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000227
joshualittc6bc58e2014-12-10 13:48:57 -0800228 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
229 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000230 } else {
231 // compute transformed (1, 0) and (0, 1) vectors
232 SkVector vec[2] = {
233 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
234 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
235 };
236
237 vec[0].normalize();
238 vec[0].scale(SK_ScalarHalf);
239 vec[1].normalize();
240 vec[1].scale(SK_ScalarHalf);
241
robertphillips@google.com91b71162013-05-10 14:09:54 +0000242 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000243 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
joshualittc6bc58e2014-12-10 13:48:57 -0800244 rect.fRight, rect.fBottom, vertexStride);
245 combinedMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000246
robertphillips@google.com91b71162013-05-10 14:09:54 +0000247 // Now create the inset points and then outset the original
248 // rotated points
249
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000250 // TL
joshualittc6bc58e2014-12-10 13:48:57 -0800251 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
252 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
253 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000254 // BL
joshualittc6bc58e2014-12-10 13:48:57 -0800255 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
256 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
257 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000258 // BR
joshualittc6bc58e2014-12-10 13:48:57 -0800259 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
260 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
261 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000262 // TR
joshualittc6bc58e2014-12-10 13:48:57 -0800263 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
264 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
265 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000266 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267
bsalomon9c0822a2014-08-11 11:07:48 -0700268 // 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 +0000269 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000270 for (int i = 0; i < 4; ++i) {
joshualittc6bc58e2014-12-10 13:48:57 -0800271 if (kUseCoverage_CoverageAttribType == type) {
272 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
273 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700274 } else {
joshualittc6bc58e2014-12-10 13:48:57 -0800275 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700276 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000277 }
278
robertphillips@google.com908aed82013-05-28 13:16:20 +0000279 int scale;
280 if (inset < SK_ScalarHalf) {
281 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
282 SkASSERT(scale >= 0 && scale <= 255);
283 } else {
284 scale = 0xff;
285 }
286
joshualittc6bc58e2014-12-10 13:48:57 -0800287 verts += 4 * vertexStride;
egdaniele27065a2014-11-06 08:00:48 -0800288
289 float innerCoverage = GrNormalizeByteToFloat(scale);
290 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
291
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000292 for (int i = 0; i < 4; ++i) {
joshualittc6bc58e2014-12-10 13:48:57 -0800293 if (kUseCoverage_CoverageAttribType == type) {
294 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
295 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700296 } else {
joshualittc6bc58e2014-12-10 13:48:57 -0800297 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700298 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000299 }
300
301 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800302 target->drawIndexedInstances(drawState,
joshualittc6bc58e2014-12-10 13:48:57 -0800303 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800304 kTriangles_GrPrimitiveType,
305 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000306 kVertsPerAAFillRect,
307 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000308 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000309}
310
joshualittb44293e2014-10-28 08:12:18 -0700311void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800312 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800313 GrColor color,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000314 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000315 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000316 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700317 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000318 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700319 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000320 if (width > 0) {
321 devStrokeSize.set(width, width);
322 combinedMatrix.mapVectors(&devStrokeSize, 1);
323 devStrokeSize.setAbs(devStrokeSize);
324 } else {
325 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
326 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000327
robertphillips@google.com18136d12013-05-10 11:05:58 +0000328 const SkScalar dx = devStrokeSize.fX;
329 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000330 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
331 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000332
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000333 // Temporarily #if'ed out. We don't want to pass in the devRect but
334 // right now it is computed in GrContext::apply_aa_to_rect and we don't
335 // want to throw away the work
336#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000337 SkRect devRect;
338 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000339#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000340
bsalomon@google.com81712882012-11-01 17:12:34 +0000341 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000342 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000343 SkScalar w = devRect.width() - dx;
344 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000345 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000346 }
347
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000348 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000349 devOutside.outset(rx, ry);
350
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000351 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700352 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000353 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700354 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
355 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000356 miterStroke = false;
357 }
358
359 if (spare <= 0 && miterStroke) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800360 this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000361 return;
362 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000363
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000364 SkRect devInside(devRect);
365 devInside.inset(rx, ry);
366
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000367 SkRect devOutsideAssist(devRect);
368
369 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
370 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000371 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000372 if (!miterStroke) {
373 devOutside.inset(0, ry);
374 devOutsideAssist.outset(0, ry);
375 }
376
joshualitt2e3b3e32014-12-09 13:31:14 -0800377 this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
joshualitt9853cce2014-11-17 14:22:48 -0800378 miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000379}
380
joshualittb44293e2014-10-28 08:12:18 -0700381void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800382 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800383 GrColor color,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000384 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000385 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000386 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000387 bool miterStroke) {
joshualitt5478d422014-11-14 16:00:38 -0800388 GrDrawState::AutoRestoreEffects are(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700389
joshualittc6bc58e2014-12-10 13:48:57 -0800390 CoverageAttribType type;
391 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
392
393 if (kUseCoverage_CoverageAttribType == type && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700394 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
395 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000396
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000397 int innerVertexNum = 4;
398 int outerVertexNum = miterStroke ? 4 : 8;
399 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
400
joshualittc6bc58e2014-12-10 13:48:57 -0800401 size_t vstride = gp->getVertexStride();
joshualitt2dd1ae02014-12-03 06:24:10 -0800402 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000403 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700404 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000405 return;
406 }
joshualittb44293e2014-10-28 08:12:18 -0700407 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000408 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700409 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000410 return;
411 }
412
413 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
414
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000415 // We create vertices for four nested rectangles. There are two ramps from 0 to full
416 // coverage, one on the exterior of the stroke and the other on the interior.
417 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000418 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700419 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
420 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
421 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000422
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000423#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000424 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700425 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000426 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
427 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
428 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000429 if (miterStroke) {
430 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
431 } else {
432 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
433 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000434 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000435#else
436 SkScalar inset = SK_ScalarHalf;
437#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000438
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000439 if (miterStroke) {
440 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700441 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000442 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700443 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
444 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000445 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700446 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000447 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700448 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
449 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000450 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700451 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
452 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000453 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700454 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
455 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000456 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700457 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000458 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700459 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000460 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000461
bsalomon9c0822a2014-08-11 11:07:48 -0700462 // 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 +0000463 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000464 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000465 for (int i = 0; i < outerVertexNum; ++i) {
joshualittc6bc58e2014-12-10 13:48:57 -0800466 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700467 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800468 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700469 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700470 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700471 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000472 }
473
bsalomon9c0822a2014-08-11 11:07:48 -0700474 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000475 int scale;
476 if (inset < SK_ScalarHalf) {
477 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
478 SkASSERT(scale >= 0 && scale <= 255);
479 } else {
480 scale = 0xff;
481 }
482
egdaniele27065a2014-11-06 08:00:48 -0800483 float innerCoverage = GrNormalizeByteToFloat(scale);
484 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700485
egdaniele27065a2014-11-06 08:00:48 -0800486 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000487 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
joshualittc6bc58e2014-12-10 13:48:57 -0800488 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700489 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800490 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700491 } else {
egdaniele27065a2014-11-06 08:00:48 -0800492 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700493 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000494 }
495
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000496 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700497 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000498 for (int i = 0; i < innerVertexNum; ++i) {
joshualittc6bc58e2014-12-10 13:48:57 -0800499 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700500 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
501 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700502 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700503 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700504 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000505 }
506
507 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800508 target->drawIndexedInstances(drawState,
joshualittc6bc58e2014-12-10 13:48:57 -0800509 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800510 kTriangles_GrPrimitiveType,
511 1,
512 totalVertexNum,
513 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700514 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000515}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000516
joshualittb44293e2014-10-28 08:12:18 -0700517void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800518 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800519 GrColor color,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000520 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700521 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000522 SkASSERT(combinedMatrix.rectStaysRect());
523 SkASSERT(!rects[1].isEmpty());
524
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000525 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000526 combinedMatrix.mapRect(&devOutside, rects[0]);
527 // can't call mapRect for devInside since it calls sort
528 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
529
530 if (devInside.isEmpty()) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800531 this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000532 return;
533 }
534
joshualitt2e3b3e32014-12-09 13:31:14 -0800535 this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
536 true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000537}