blob: edb59d04d85361fea960930484974d0c64e9ee20 [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) {
30 if (drawState->canTweakAlphaForCoverage()) {
joshualitt5478d422014-11-14 16:00:38 -080031 drawState->setGeometryProcessor(
32 GrDefaultGeoProcFactory::CreateAndSetAttribs(
33 drawState,
34 GrDefaultGeoProcFactory::kColor_GPType))->unref();
bsalomonc30aaa02014-08-13 07:15:29 -070035 return kUseColor_CoverageAttribType;
36 } else {
joshualitt5478d422014-11-14 16:00:38 -080037 drawState->setGeometryProcessor(
38 GrDefaultGeoProcFactory::CreateAndSetAttribs(
39 drawState,
40 GrDefaultGeoProcFactory::kColor_GPType |
41 GrDefaultGeoProcFactory::kCoverage_GPType))->unref();
bsalomonc30aaa02014-08-13 07:15:29 -070042 return kUseCoverage_CoverageAttribType;
43 }
44}
45
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000046static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000047 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000048 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
49 r.fRight - dx, r.fBottom - dy, stride);
50}
51
robertphillips@google.comf6747b02012-06-12 00:32:28 +000052void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000053 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000054 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
55 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000056}
57
robertphillips@google.com6d067302012-12-18 21:47:47 +000058static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000059 0, 1, 5, 5, 4, 0,
60 1, 2, 6, 6, 5, 1,
61 2, 3, 7, 7, 6, 2,
62 3, 0, 4, 4, 7, 3,
63 4, 5, 6, 6, 7, 4,
64};
65
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000066static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000067static const int kVertsPerAAFillRect = 8;
68static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000069
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000070static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000071 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
72 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
73 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
74 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
75
76 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
77 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
78 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
79 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
80
81 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
82 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
83 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
84 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
85};
86
joshualitt5ead6da2014-10-22 16:00:29 -070087static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
88static const int kVertsPerMiterStrokeRect = 16;
89static const int kNumMiterStrokeRectsInIndexBuffer = 256;
90
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000091/**
92 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
93 * from the first index. The index layout:
94 * outer AA line: 0~3, 4~7
95 * outer edge: 8~11, 12~15
96 * inner edge: 16~19
97 * inner AA line: 20~23
98 * Following comes a bevel-stroke rect and its indices:
99 *
100 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000101 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000102 * * ______________________________ *
103 * * / 12 15 \ *
104 * * / \ *
105 * 0 * |8 16_____________________19 11 | * 3
106 * * | | | | *
107 * * | | **************** | | *
108 * * | | * 20 23 * | | *
109 * * | | * * | | *
110 * * | | * 21 22 * | | *
111 * * | | **************** | | *
112 * * | |____________________| | *
113 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000114 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000115 * * \13 __________________________14/ *
116 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000117 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000118 * 5 6
119 */
120static const uint16_t gBevelStrokeAARectIdx[] = {
121 // Draw outer AA, from outer AA line to outer edge, shift is 0.
122 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
123 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
124 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
125 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
126 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
127 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
128 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
129 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
130
131 // Draw the stroke, from outer edge to inner edge, shift is 8.
132 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
133 1 + 8, 5 + 8, 9 + 8,
134 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
135 6 + 8, 2 + 8, 10 + 8,
136 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
137 3 + 8, 7 + 8, 11 + 8,
138 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
139 4 + 8, 0 + 8, 8 + 8,
140
141 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
142 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
143 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
144 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
145 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
146};
147
joshualitt5ead6da2014-10-22 16:00:29 -0700148static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
149static const int kVertsPerBevelStrokeRect = 24;
150static const int kNumBevelStrokeRectsInIndexBuffer = 256;
151
joshualittb44293e2014-10-28 08:12:18 -0700152static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000153 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
154 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000155}
156
joshualittb44293e2014-10-28 08:12:18 -0700157GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000158 if (miterStroke) {
159 if (NULL == fAAMiterStrokeRectIndexBuffer) {
160 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700161 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
162 kIndicesPerMiterStrokeRect,
163 kNumMiterStrokeRectsInIndexBuffer,
164 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000165 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000166 return fAAMiterStrokeRectIndexBuffer;
167 } else {
168 if (NULL == fAABevelStrokeRectIndexBuffer) {
169 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700170 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
171 kIndicesPerBevelStrokeRect,
172 kNumBevelStrokeRectsInIndexBuffer,
173 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000174 }
175 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000176 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000177}
178
joshualittb44293e2014-10-28 08:12:18 -0700179void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800180 GrDrawState* drawState,
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
bsalomon9c0822a2014-08-11 11:07:48 -0700186 GrColor color = drawState->getColor();
187
bsalomonc30aaa02014-08-13 07:15:29 -0700188 CoverageAttribType covAttribType = set_rect_attribs(drawState);
189 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700190 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
191 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000192
joshualitt9853cce2014-11-17 14:22:48 -0800193 GrDrawTarget::AutoReleaseGeometry geo(target, 8, drawState->getVertexStride(), 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());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700212 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000213
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000214 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700215 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
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
egdaniel7b3d5ee2014-08-28 05:41:14 -0700229 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
230 set_inset_fan(fan1Pos, vstride, 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,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700245 rect.fRight, rect.fBottom, vstride);
246 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 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
egdaniel7b3d5ee2014-08-28 05:41:14 -0700252 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
253 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
254 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000255 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700256 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
257 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
258 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000259 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700260 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
261 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
262 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000263 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700264 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
265 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
266 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += 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) {
bsalomonc30aaa02014-08-13 07:15:29 -0700272 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700273 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800274 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700275 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700276 *reinterpret_cast<GrColor*>(verts + i * vstride) = 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
egdaniel7b3d5ee2014-08-28 05:41:14 -0700288 verts += 4 * vstride;
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) {
bsalomonc30aaa02014-08-13 07:15:29 -0700294 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700295 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800296 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700297 } else {
egdaniele27065a2014-11-06 08:00:48 -0800298 *reinterpret_cast<GrColor*>(verts + i * vstride) = 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,
304 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,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000313 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000314 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000315 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700316 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000317 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700318 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000319 if (width > 0) {
320 devStrokeSize.set(width, width);
321 combinedMatrix.mapVectors(&devStrokeSize, 1);
322 devStrokeSize.setAbs(devStrokeSize);
323 } else {
324 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
325 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000326
robertphillips@google.com18136d12013-05-10 11:05:58 +0000327 const SkScalar dx = devStrokeSize.fX;
328 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000329 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
330 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000331
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000332 // Temporarily #if'ed out. We don't want to pass in the devRect but
333 // right now it is computed in GrContext::apply_aa_to_rect and we don't
334 // want to throw away the work
335#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000336 SkRect devRect;
337 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000338#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000339
bsalomon@google.com81712882012-11-01 17:12:34 +0000340 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000341 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000342 SkScalar w = devRect.width() - dx;
343 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000344 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000345 }
346
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000347 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000348 devOutside.outset(rx, ry);
349
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000350 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700351 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000352 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700353 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
354 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000355 miterStroke = false;
356 }
357
358 if (spare <= 0 && miterStroke) {
joshualitt9853cce2014-11-17 14:22:48 -0800359 this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000360 return;
361 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000362
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000363 SkRect devInside(devRect);
364 devInside.inset(rx, ry);
365
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000366 SkRect devOutsideAssist(devRect);
367
368 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
369 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000370 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000371 if (!miterStroke) {
372 devOutside.inset(0, ry);
373 devOutsideAssist.outset(0, ry);
374 }
375
joshualitt9853cce2014-11-17 14:22:48 -0800376 this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside,
377 miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000378}
379
joshualittb44293e2014-10-28 08:12:18 -0700380void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800381 GrDrawState* drawState,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000382 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000383 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000384 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000385 bool miterStroke) {
joshualitt5478d422014-11-14 16:00:38 -0800386 GrDrawState::AutoRestoreEffects are(drawState);
bsalomonc30aaa02014-08-13 07:15:29 -0700387 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700388
389 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700390 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700391 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
392 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000393
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000394 int innerVertexNum = 4;
395 int outerVertexNum = miterStroke ? 4 : 8;
396 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
397
joshualitt9853cce2014-11-17 14:22:48 -0800398 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, drawState->getVertexStride(), 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());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700410 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000411
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000412 // We create vertices for four nested rectangles. There are two ramps from 0 to full
413 // coverage, one on the exterior of the stroke and the other on the interior.
414 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000415 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700416 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
417 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
418 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000419
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000420#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000421 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700422 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000423 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
424 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
425 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000426 if (miterStroke) {
427 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
428 } else {
429 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
430 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000431 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000432#else
433 SkScalar inset = SK_ScalarHalf;
434#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000435
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000436 if (miterStroke) {
437 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700438 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000439 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700440 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
441 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000442 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700443 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000444 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700445 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
446 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000447 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700448 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
449 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000450 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700451 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
452 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000453 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700454 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000455 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700456 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000457 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000458
bsalomon9c0822a2014-08-11 11:07:48 -0700459 // 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 +0000460 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000461 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000462 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700463 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700464 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800465 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700466 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700467 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700468 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000469 }
470
bsalomon9c0822a2014-08-11 11:07:48 -0700471 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000472 int scale;
473 if (inset < SK_ScalarHalf) {
474 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
475 SkASSERT(scale >= 0 && scale <= 255);
476 } else {
477 scale = 0xff;
478 }
479
egdaniele27065a2014-11-06 08:00:48 -0800480 float innerCoverage = GrNormalizeByteToFloat(scale);
481 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700482
egdaniele27065a2014-11-06 08:00:48 -0800483 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000484 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700485 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700486 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800487 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700488 } else {
egdaniele27065a2014-11-06 08:00:48 -0800489 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700490 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000491 }
492
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000493 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700494 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000495 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700496 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700497 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
498 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700499 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700500 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700501 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000502 }
503
504 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800505 target->drawIndexedInstances(drawState,
506 kTriangles_GrPrimitiveType,
507 1,
508 totalVertexNum,
509 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700510 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000511}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000512
joshualittb44293e2014-10-28 08:12:18 -0700513void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800514 GrDrawState* drawState,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000515 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700516 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000517 SkASSERT(combinedMatrix.rectStaysRect());
518 SkASSERT(!rects[1].isEmpty());
519
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000520 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000521 combinedMatrix.mapRect(&devOutside, rects[0]);
522 // can't call mapRect for devInside since it calls sort
523 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
524
525 if (devInside.isEmpty()) {
joshualitt9853cce2014-11-17 14:22:48 -0800526 this->fillAARect(target, drawState, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000527 return;
528 }
529
joshualitt9853cce2014-11-17 14:22:48 -0800530 this->geometryStrokeAARect(target, drawState, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000531}