blob: f748895ba807ac51d8ab9b67e9a36016cc1f069d [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,
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) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000183 GrDrawState* drawState = target->drawState();
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
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000193 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 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);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000303 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
304 kVertsPerAAFillRect,
305 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000306 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000307}
308
joshualittb44293e2014-10-28 08:12:18 -0700309void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000310 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000311 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000312 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700313 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000314 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700315 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000316 if (width > 0) {
317 devStrokeSize.set(width, width);
318 combinedMatrix.mapVectors(&devStrokeSize, 1);
319 devStrokeSize.setAbs(devStrokeSize);
320 } else {
321 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
322 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000323
robertphillips@google.com18136d12013-05-10 11:05:58 +0000324 const SkScalar dx = devStrokeSize.fX;
325 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000326 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
327 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000328
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000329 // Temporarily #if'ed out. We don't want to pass in the devRect but
330 // right now it is computed in GrContext::apply_aa_to_rect and we don't
331 // want to throw away the work
332#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000333 SkRect devRect;
334 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000335#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000336
bsalomon@google.com81712882012-11-01 17:12:34 +0000337 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000338 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000339 SkScalar w = devRect.width() - dx;
340 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000341 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000342 }
343
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000344 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000345 devOutside.outset(rx, ry);
346
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000347 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700348 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000349 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700350 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
351 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000352 miterStroke = false;
353 }
354
355 if (spare <= 0 && miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700356 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000357 return;
358 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000359
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000360 SkRect devInside(devRect);
361 devInside.inset(rx, ry);
362
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000363 SkRect devOutsideAssist(devRect);
364
365 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
366 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000367 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000368 if (!miterStroke) {
369 devOutside.inset(0, ry);
370 devOutsideAssist.outset(0, ry);
371 }
372
joshualittb44293e2014-10-28 08:12:18 -0700373 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000374}
375
joshualittb44293e2014-10-28 08:12:18 -0700376void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000377 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000378 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000379 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000380 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000381 GrDrawState* drawState = target->drawState();
joshualitt5478d422014-11-14 16:00:38 -0800382 GrDrawState::AutoRestoreEffects are(drawState);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000383
bsalomonc30aaa02014-08-13 07:15:29 -0700384 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700385
386 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700387 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700388 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
389 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000390
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000391 int innerVertexNum = 4;
392 int outerVertexNum = miterStroke ? 4 : 8;
393 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
394
395 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000396 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700397 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000398 return;
399 }
joshualittb44293e2014-10-28 08:12:18 -0700400 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000401 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700402 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000403 return;
404 }
405
406 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700407 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000408
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000409 // We create vertices for four nested rectangles. There are two ramps from 0 to full
410 // coverage, one on the exterior of the stroke and the other on the interior.
411 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000412 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700413 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
414 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
415 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000416
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000417#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000418 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700419 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000420 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
421 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
422 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000423 if (miterStroke) {
424 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
425 } else {
426 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
427 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000428 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000429#else
430 SkScalar inset = SK_ScalarHalf;
431#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000432
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000433 if (miterStroke) {
434 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700435 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000436 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700437 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
438 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000439 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700440 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000441 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700442 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
443 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000444 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700445 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
446 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000447 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700448 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
449 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000450 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700451 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000452 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700453 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000454 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000455
bsalomon9c0822a2014-08-11 11:07:48 -0700456 // 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 +0000457 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000458 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000459 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700460 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700461 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800462 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700463 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700464 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700465 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000466 }
467
bsalomon9c0822a2014-08-11 11:07:48 -0700468 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000469 int scale;
470 if (inset < SK_ScalarHalf) {
471 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
472 SkASSERT(scale >= 0 && scale <= 255);
473 } else {
474 scale = 0xff;
475 }
476
egdaniele27065a2014-11-06 08:00:48 -0800477 float innerCoverage = GrNormalizeByteToFloat(scale);
478 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700479
egdaniele27065a2014-11-06 08:00:48 -0800480 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000481 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700482 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700483 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800484 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700485 } else {
egdaniele27065a2014-11-06 08:00:48 -0800486 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700487 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000488 }
489
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000490 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700491 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000492 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700493 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700494 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
495 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700496 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700497 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700498 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000499 }
500
501 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700502 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
joshualittb44293e2014-10-28 08:12:18 -0700503 totalVertexNum, aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700504 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000505}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000506
joshualittb44293e2014-10-28 08:12:18 -0700507void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000508 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700509 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000510 SkASSERT(combinedMatrix.rectStaysRect());
511 SkASSERT(!rects[1].isEmpty());
512
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000513 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000514 combinedMatrix.mapRect(&devOutside, rects[0]);
515 // can't call mapRect for devInside since it calls sort
516 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
517
518 if (devInside.isEmpty()) {
joshualittb44293e2014-10-28 08:12:18 -0700519 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000520 return;
521 }
522
joshualittb44293e2014-10-28 08:12:18 -0700523 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000524}