blob: 95fe8c9b7f6523dfc40074ab95787c6ac002d691 [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"
joshualittb0a8a372014-09-23 09:50:21 -070013#include "GrTBackendProcessorFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
joshualitt5478d422014-11-14 16:00:38 -080015#include "gl/GrGLProcessor.h"
16#include "gl/GrGLGeometryProcessor.h"
17#include "gl/builders/GrGLProgramBuilder.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000018
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000019///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000020
robertphillips@google.comf6747b02012-06-12 00:32:28 +000021namespace {
bsalomonc30aaa02014-08-13 07:15:29 -070022// Should the coverage be multiplied into the color attrib or use a separate attrib.
23enum CoverageAttribType {
24 kUseColor_CoverageAttribType,
25 kUseCoverage_CoverageAttribType,
26};
27}
28
29static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
joshualitt2dd1ae02014-12-03 06:24:10 -080030 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
bsalomonc30aaa02014-08-13 07:15:29 -070031 if (drawState->canTweakAlphaForCoverage()) {
joshualitt2dd1ae02014-12-03 06:24:10 -080032 drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
33 SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
34 sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
bsalomonc30aaa02014-08-13 07:15:29 -070035 return kUseColor_CoverageAttribType;
36 } else {
joshualitt2dd1ae02014-12-03 06:24:10 -080037 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
38 drawState->setGeometryProcessor(GrDefaultGeoProcFactory::Create(flags))->unref();
39 SkASSERT(drawState->getGeometryProcessor()->getVertexStride() ==
40 sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
bsalomonc30aaa02014-08-13 07:15:29 -070041 return kUseCoverage_CoverageAttribType;
42 }
43}
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,
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
bsalomon9c0822a2014-08-11 11:07:48 -0700185 GrColor color = drawState->getColor();
186
bsalomonc30aaa02014-08-13 07:15:29 -0700187 CoverageAttribType covAttribType = set_rect_attribs(drawState);
188 if (kUseCoverage_CoverageAttribType == covAttribType && 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
joshualitt2dd1ae02014-12-03 06:24:10 -0800192 size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
193 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vstride, 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);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700214 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
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
egdaniel7b3d5ee2014-08-28 05:41:14 -0700228 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
229 set_inset_fan(fan1Pos, vstride, 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,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700244 rect.fRight, rect.fBottom, vstride);
245 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 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
egdaniel7b3d5ee2014-08-28 05:41:14 -0700251 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
252 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
253 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000254 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700255 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
256 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
257 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000258 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700259 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
260 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
261 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000262 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700263 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
264 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
265 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += 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) {
bsalomonc30aaa02014-08-13 07:15:29 -0700271 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700272 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800273 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700274 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700275 *reinterpret_cast<GrColor*>(verts + i * vstride) = 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
egdaniel7b3d5ee2014-08-28 05:41:14 -0700287 verts += 4 * vstride;
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) {
bsalomonc30aaa02014-08-13 07:15:29 -0700293 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700294 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800295 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700296 } else {
egdaniele27065a2014-11-06 08:00:48 -0800297 *reinterpret_cast<GrColor*>(verts + i * vstride) = 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,
303 kTriangles_GrPrimitiveType,
304 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000305 kVertsPerAAFillRect,
306 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000307 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000308}
309
joshualittb44293e2014-10-28 08:12:18 -0700310void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800311 GrDrawState* drawState,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000312 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000313 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000314 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700315 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000316 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700317 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000318 if (width > 0) {
319 devStrokeSize.set(width, width);
320 combinedMatrix.mapVectors(&devStrokeSize, 1);
321 devStrokeSize.setAbs(devStrokeSize);
322 } else {
323 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
324 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000325
robertphillips@google.com18136d12013-05-10 11:05:58 +0000326 const SkScalar dx = devStrokeSize.fX;
327 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000328 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
329 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000330
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000331 // Temporarily #if'ed out. We don't want to pass in the devRect but
332 // right now it is computed in GrContext::apply_aa_to_rect and we don't
333 // want to throw away the work
334#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000335 SkRect devRect;
336 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000337#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000338
bsalomon@google.com81712882012-11-01 17:12:34 +0000339 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000340 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000341 SkScalar w = devRect.width() - dx;
342 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000343 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000344 }
345
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000346 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000347 devOutside.outset(rx, ry);
348
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000349 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700350 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000351 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700352 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
353 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000354 miterStroke = false;
355 }
356
357 if (spare <= 0 && miterStroke) {
joshualitt9853cce2014-11-17 14:22:48 -0800358 this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000359 return;
360 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000361
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000362 SkRect devInside(devRect);
363 devInside.inset(rx, ry);
364
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000365 SkRect devOutsideAssist(devRect);
366
367 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
368 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000369 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000370 if (!miterStroke) {
371 devOutside.inset(0, ry);
372 devOutsideAssist.outset(0, ry);
373 }
374
joshualitt9853cce2014-11-17 14:22:48 -0800375 this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside,
376 miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000377}
378
joshualittb44293e2014-10-28 08:12:18 -0700379void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800380 GrDrawState* drawState,
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);
bsalomonc30aaa02014-08-13 07:15:29 -0700386 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700387
388 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700389 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700390 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
391 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000392
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000393 int innerVertexNum = 4;
394 int outerVertexNum = miterStroke ? 4 : 8;
395 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
396
joshualitt2dd1ae02014-12-03 06:24:10 -0800397 size_t vstride = drawState->getGeometryProcessor()->getVertexStride();
398 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000399 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700400 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000401 return;
402 }
joshualittb44293e2014-10-28 08:12:18 -0700403 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000404 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700405 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000406 return;
407 }
408
409 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
410
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000411 // We create vertices for four nested rectangles. There are two ramps from 0 to full
412 // coverage, one on the exterior of the stroke and the other on the interior.
413 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000414 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700415 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
416 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
417 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000418
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000419#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000420 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700421 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000422 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
423 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
424 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000425 if (miterStroke) {
426 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
427 } else {
428 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
429 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000430 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000431#else
432 SkScalar inset = SK_ScalarHalf;
433#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000434
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000435 if (miterStroke) {
436 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700437 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000438 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700439 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
440 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000441 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700442 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000443 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700444 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
445 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000446 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700447 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
448 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000449 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700450 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
451 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000452 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700453 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000454 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700455 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000456 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000457
bsalomon9c0822a2014-08-11 11:07:48 -0700458 // 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 +0000459 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000460 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000461 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700462 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700463 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800464 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700465 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700466 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700467 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000468 }
469
bsalomon9c0822a2014-08-11 11:07:48 -0700470 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000471 int scale;
472 if (inset < SK_ScalarHalf) {
473 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
474 SkASSERT(scale >= 0 && scale <= 255);
475 } else {
476 scale = 0xff;
477 }
478
egdaniele27065a2014-11-06 08:00:48 -0800479 float innerCoverage = GrNormalizeByteToFloat(scale);
480 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700481
egdaniele27065a2014-11-06 08:00:48 -0800482 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000483 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700484 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700485 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800486 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700487 } else {
egdaniele27065a2014-11-06 08:00:48 -0800488 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700489 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000490 }
491
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000492 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700493 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000494 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700495 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700496 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
497 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700498 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700499 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700500 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000501 }
502
503 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800504 target->drawIndexedInstances(drawState,
505 kTriangles_GrPrimitiveType,
506 1,
507 totalVertexNum,
508 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700509 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000510}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000511
joshualittb44293e2014-10-28 08:12:18 -0700512void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800513 GrDrawState* drawState,
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()) {
joshualitt9853cce2014-11-17 14:22:48 -0800525 this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000526 return;
527 }
528
joshualitt9853cce2014-11-17 14:22:48 -0800529 this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000530}