blob: 46196e2e4ef542d8e3d8a70d8e7fcc377b59b1f7 [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"
robertphillips@google.comf6747b02012-06-12 00:32:28 +00009#include "GrGpu.h"
joshualitt47bb3822014-10-07 16:43:25 -070010#include "gl/builders/GrGLProgramBuilder.h"
joshualittb0a8a372014-09-23 09:50:21 -070011#include "gl/GrGLProcessor.h"
joshualitt249af152014-09-15 11:41:13 -070012#include "gl/GrGLGeometryProcessor.h"
joshualittb0a8a372014-09-23 09:50:21 -070013#include "GrTBackendProcessorFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
joshualittb0a8a372014-09-23 09:50:21 -070015#include "GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000016
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000017///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000018
robertphillips@google.comf6747b02012-06-12 00:32:28 +000019namespace {
bsalomon9c0822a2014-08-11 11:07:48 -070020extern const GrVertexAttrib gAARectAttribs[] = {
21 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
22 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
egdaniele27065a2014-11-06 08:00:48 -080023 {kFloat_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +000024};
25
bsalomonc30aaa02014-08-13 07:15:29 -070026// Should the coverage be multiplied into the color attrib or use a separate attrib.
27enum CoverageAttribType {
28 kUseColor_CoverageAttribType,
29 kUseCoverage_CoverageAttribType,
30};
31}
32
33static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
34 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -070035 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -070036 return kUseColor_CoverageAttribType;
37 } else {
egdaniele27065a2014-11-06 08:00:48 -080038 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + sizeof(SkColor) +
39 sizeof(float));
bsalomonc30aaa02014-08-13 07:15:29 -070040 return kUseCoverage_CoverageAttribType;
41 }
42}
43
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000044static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000045 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000046 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
47 r.fRight - dx, r.fBottom - dy, stride);
48}
49
robertphillips@google.comf6747b02012-06-12 00:32:28 +000050void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000051 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000052 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
53 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000054}
55
robertphillips@google.com6d067302012-12-18 21:47:47 +000056static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000057 0, 1, 5, 5, 4, 0,
58 1, 2, 6, 6, 5, 1,
59 2, 3, 7, 7, 6, 2,
60 3, 0, 4, 4, 7, 3,
61 4, 5, 6, 6, 7, 4,
62};
63
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000064static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000065static const int kVertsPerAAFillRect = 8;
66static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000067
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000068static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000069 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
70 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
71 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
72 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
73
74 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
75 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
76 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
77 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
78
79 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
80 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
81 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
82 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
83};
84
joshualitt5ead6da2014-10-22 16:00:29 -070085static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
86static const int kVertsPerMiterStrokeRect = 16;
87static const int kNumMiterStrokeRectsInIndexBuffer = 256;
88
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000089/**
90 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
91 * from the first index. The index layout:
92 * outer AA line: 0~3, 4~7
93 * outer edge: 8~11, 12~15
94 * inner edge: 16~19
95 * inner AA line: 20~23
96 * Following comes a bevel-stroke rect and its indices:
97 *
98 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +000099 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000100 * * ______________________________ *
101 * * / 12 15 \ *
102 * * / \ *
103 * 0 * |8 16_____________________19 11 | * 3
104 * * | | | | *
105 * * | | **************** | | *
106 * * | | * 20 23 * | | *
107 * * | | * * | | *
108 * * | | * 21 22 * | | *
109 * * | | **************** | | *
110 * * | |____________________| | *
111 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000112 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000113 * * \13 __________________________14/ *
114 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000115 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000116 * 5 6
117 */
118static const uint16_t gBevelStrokeAARectIdx[] = {
119 // Draw outer AA, from outer AA line to outer edge, shift is 0.
120 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
121 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
122 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
123 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
124 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
125 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
126 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
127 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
128
129 // Draw the stroke, from outer edge to inner edge, shift is 8.
130 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
131 1 + 8, 5 + 8, 9 + 8,
132 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
133 6 + 8, 2 + 8, 10 + 8,
134 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
135 3 + 8, 7 + 8, 11 + 8,
136 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
137 4 + 8, 0 + 8, 8 + 8,
138
139 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
140 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
141 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
142 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
143 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
144};
145
joshualitt5ead6da2014-10-22 16:00:29 -0700146static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
147static const int kVertsPerBevelStrokeRect = 24;
148static const int kNumBevelStrokeRectsInIndexBuffer = 256;
149
joshualittb44293e2014-10-28 08:12:18 -0700150static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000151 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
152 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000153}
154
joshualittb44293e2014-10-28 08:12:18 -0700155GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000156 if (miterStroke) {
157 if (NULL == fAAMiterStrokeRectIndexBuffer) {
158 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700159 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
160 kIndicesPerMiterStrokeRect,
161 kNumMiterStrokeRectsInIndexBuffer,
162 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000163 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000164 return fAAMiterStrokeRectIndexBuffer;
165 } else {
166 if (NULL == fAABevelStrokeRectIndexBuffer) {
167 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700168 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
169 kIndicesPerBevelStrokeRect,
170 kNumBevelStrokeRectsInIndexBuffer,
171 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000172 }
173 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000174 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000175}
176
joshualittb44293e2014-10-28 08:12:18 -0700177void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000178 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000179 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700180 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000181 GrDrawState* drawState = target->drawState();
182
bsalomon9c0822a2014-08-11 11:07:48 -0700183 GrColor color = drawState->getColor();
184
bsalomonc30aaa02014-08-13 07:15:29 -0700185 CoverageAttribType covAttribType = set_rect_attribs(drawState);
186 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700187 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
188 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000189
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000190 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000191 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700192 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000193 return;
194 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000195
joshualitt5ead6da2014-10-22 16:00:29 -0700196 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700197 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
198 kIndicesPerAAFillRect,
199 kNumAAFillRectsInIndexBuffer,
200 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700201 }
202 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000203 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700204 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000205 return;
206 }
207
208 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700209 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000210
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000211 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700212 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000213
robertphillips@google.com908aed82013-05-28 13:16:20 +0000214 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
215 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
216
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000217 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000218 // Temporarily #if'ed out. We don't want to pass in the devRect but
219 // right now it is computed in GrContext::apply_aa_to_rect and we don't
220 // want to throw away the work
221#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000222 SkRect devRect;
223 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000224#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000225
egdaniel7b3d5ee2014-08-28 05:41:14 -0700226 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
227 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000228 } else {
229 // compute transformed (1, 0) and (0, 1) vectors
230 SkVector vec[2] = {
231 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
232 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
233 };
234
235 vec[0].normalize();
236 vec[0].scale(SK_ScalarHalf);
237 vec[1].normalize();
238 vec[1].scale(SK_ScalarHalf);
239
robertphillips@google.com91b71162013-05-10 14:09:54 +0000240 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000241 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700242 rect.fRight, rect.fBottom, vstride);
243 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000244
robertphillips@google.com91b71162013-05-10 14:09:54 +0000245 // Now create the inset points and then outset the original
246 // rotated points
247
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000248 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700249 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
250 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
251 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000252 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700253 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
254 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
255 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000256 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700257 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
258 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
259 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000260 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700261 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
262 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
263 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000264 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000265
bsalomon9c0822a2014-08-11 11:07:48 -0700266 // 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 +0000267 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700269 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700270 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800271 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700272 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700273 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700274 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000275 }
276
robertphillips@google.com908aed82013-05-28 13:16:20 +0000277 int scale;
278 if (inset < SK_ScalarHalf) {
279 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
280 SkASSERT(scale >= 0 && scale <= 255);
281 } else {
282 scale = 0xff;
283 }
284
egdaniel7b3d5ee2014-08-28 05:41:14 -0700285 verts += 4 * vstride;
egdaniele27065a2014-11-06 08:00:48 -0800286
287 float innerCoverage = GrNormalizeByteToFloat(scale);
288 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
289
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700291 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700292 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800293 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700294 } else {
egdaniele27065a2014-11-06 08:00:48 -0800295 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700296 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000297 }
298
299 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000300 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
301 kVertsPerAAFillRect,
302 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000303 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000304}
305
joshualittb44293e2014-10-28 08:12:18 -0700306void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000307 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000308 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000309 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700310 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000311 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700312 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000313 if (width > 0) {
314 devStrokeSize.set(width, width);
315 combinedMatrix.mapVectors(&devStrokeSize, 1);
316 devStrokeSize.setAbs(devStrokeSize);
317 } else {
318 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
319 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000320
robertphillips@google.com18136d12013-05-10 11:05:58 +0000321 const SkScalar dx = devStrokeSize.fX;
322 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000323 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
324 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000325
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000326 // Temporarily #if'ed out. We don't want to pass in the devRect but
327 // right now it is computed in GrContext::apply_aa_to_rect and we don't
328 // want to throw away the work
329#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000330 SkRect devRect;
331 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000332#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000333
bsalomon@google.com81712882012-11-01 17:12:34 +0000334 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000335 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000336 SkScalar w = devRect.width() - dx;
337 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000338 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000339 }
340
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000341 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000342 devOutside.outset(rx, ry);
343
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000344 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700345 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000346 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700347 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
348 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000349 miterStroke = false;
350 }
351
352 if (spare <= 0 && miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700353 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000354 return;
355 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000356
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000357 SkRect devInside(devRect);
358 devInside.inset(rx, ry);
359
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000360 SkRect devOutsideAssist(devRect);
361
362 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
363 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000364 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000365 if (!miterStroke) {
366 devOutside.inset(0, ry);
367 devOutsideAssist.outset(0, ry);
368 }
369
joshualittb44293e2014-10-28 08:12:18 -0700370 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000371}
372
joshualittb44293e2014-10-28 08:12:18 -0700373void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000374 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000375 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000376 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000377 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000378 GrDrawState* drawState = target->drawState();
379
bsalomonc30aaa02014-08-13 07:15:29 -0700380 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700381
382 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700383 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700384 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
385 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000386
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000387 int innerVertexNum = 4;
388 int outerVertexNum = miterStroke ? 4 : 8;
389 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
390
391 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000392 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700393 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000394 return;
395 }
joshualittb44293e2014-10-28 08:12:18 -0700396 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000397 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700398 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000399 return;
400 }
401
402 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700403 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000404
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000405 // We create vertices for four nested rectangles. There are two ramps from 0 to full
406 // coverage, one on the exterior of the stroke and the other on the interior.
407 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000408 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700409 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
410 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
411 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000412
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000413#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000414 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700415 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000416 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
417 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
418 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000419 if (miterStroke) {
420 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
421 } else {
422 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
423 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000424 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000425#else
426 SkScalar inset = SK_ScalarHalf;
427#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000428
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000429 if (miterStroke) {
430 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700431 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000432 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700433 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
434 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000435 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700436 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000437 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700438 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
439 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000440 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700441 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
442 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000443 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700444 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
445 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000446 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700447 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000448 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700449 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000450 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000451
bsalomon9c0822a2014-08-11 11:07:48 -0700452 // 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 +0000453 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000454 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000455 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700456 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700457 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800458 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700459 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700460 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700461 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000462 }
463
bsalomon9c0822a2014-08-11 11:07:48 -0700464 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000465 int scale;
466 if (inset < SK_ScalarHalf) {
467 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
468 SkASSERT(scale >= 0 && scale <= 255);
469 } else {
470 scale = 0xff;
471 }
472
egdaniele27065a2014-11-06 08:00:48 -0800473 float innerCoverage = GrNormalizeByteToFloat(scale);
474 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700475
egdaniele27065a2014-11-06 08:00:48 -0800476 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000477 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700478 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700479 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800480 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700481 } else {
egdaniele27065a2014-11-06 08:00:48 -0800482 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700483 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000484 }
485
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000486 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700487 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000488 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700489 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700490 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
491 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700492 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700493 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700494 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000495 }
496
497 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700498 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
joshualittb44293e2014-10-28 08:12:18 -0700499 totalVertexNum, aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700500 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000501}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000502
joshualittb44293e2014-10-28 08:12:18 -0700503void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000504 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700505 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000506 SkASSERT(combinedMatrix.rectStaysRect());
507 SkASSERT(!rects[1].isEmpty());
508
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000509 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000510 combinedMatrix.mapRect(&devOutside, rects[0]);
511 // can't call mapRect for devInside since it calls sort
512 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
513
514 if (devInside.isEmpty()) {
joshualittb44293e2014-10-28 08:12:18 -0700515 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000516 return;
517 }
518
joshualittb44293e2014-10-28 08:12:18 -0700519 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000520}