blob: e743ae9080acc4329eae0900818b84f7b1cd20b0 [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"
egdaniel605dd0f2014-11-12 08:35:25 -080010#include "GrInvariantOutput.h"
joshualitt47bb3822014-10-07 16:43:25 -070011#include "gl/builders/GrGLProgramBuilder.h"
joshualittb0a8a372014-09-23 09:50:21 -070012#include "gl/GrGLProcessor.h"
joshualitt249af152014-09-15 11:41:13 -070013#include "gl/GrGLGeometryProcessor.h"
joshualittb0a8a372014-09-23 09:50:21 -070014#include "GrTBackendProcessorFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000015#include "SkColorPriv.h"
joshualittb0a8a372014-09-23 09:50:21 -070016#include "GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000017
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000018///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000019
robertphillips@google.comf6747b02012-06-12 00:32:28 +000020namespace {
bsalomon9c0822a2014-08-11 11:07:48 -070021extern const GrVertexAttrib gAARectAttribs[] = {
22 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
23 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
egdaniele27065a2014-11-06 08:00:48 -080024 {kFloat_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +000025};
26
bsalomonc30aaa02014-08-13 07:15:29 -070027// Should the coverage be multiplied into the color attrib or use a separate attrib.
28enum CoverageAttribType {
29 kUseColor_CoverageAttribType,
30 kUseCoverage_CoverageAttribType,
31};
32}
33
34static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
35 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -070036 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -070037 return kUseColor_CoverageAttribType;
38 } else {
egdaniele27065a2014-11-06 08:00:48 -080039 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + sizeof(SkColor) +
40 sizeof(float));
bsalomonc30aaa02014-08-13 07:15:29 -070041 return kUseCoverage_CoverageAttribType;
42 }
43}
44
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000045static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000046 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000047 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
48 r.fRight - dx, r.fBottom - dy, stride);
49}
50
robertphillips@google.comf6747b02012-06-12 00:32:28 +000051void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000052 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000053 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
54 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000055}
56
robertphillips@google.com6d067302012-12-18 21:47:47 +000057static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000058 0, 1, 5, 5, 4, 0,
59 1, 2, 6, 6, 5, 1,
60 2, 3, 7, 7, 6, 2,
61 3, 0, 4, 4, 7, 3,
62 4, 5, 6, 6, 7, 4,
63};
64
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000065static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000066static const int kVertsPerAAFillRect = 8;
67static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000068
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000069static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000070 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
71 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
72 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
73 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
74
75 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
76 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
77 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
78 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
79
80 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
81 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
82 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
83 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
84};
85
joshualitt5ead6da2014-10-22 16:00:29 -070086static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
87static const int kVertsPerMiterStrokeRect = 16;
88static const int kNumMiterStrokeRectsInIndexBuffer = 256;
89
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000090/**
91 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
92 * from the first index. The index layout:
93 * outer AA line: 0~3, 4~7
94 * outer edge: 8~11, 12~15
95 * inner edge: 16~19
96 * inner AA line: 20~23
97 * Following comes a bevel-stroke rect and its indices:
98 *
99 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000100 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000101 * * ______________________________ *
102 * * / 12 15 \ *
103 * * / \ *
104 * 0 * |8 16_____________________19 11 | * 3
105 * * | | | | *
106 * * | | **************** | | *
107 * * | | * 20 23 * | | *
108 * * | | * * | | *
109 * * | | * 21 22 * | | *
110 * * | | **************** | | *
111 * * | |____________________| | *
112 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000113 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000114 * * \13 __________________________14/ *
115 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000116 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000117 * 5 6
118 */
119static const uint16_t gBevelStrokeAARectIdx[] = {
120 // Draw outer AA, from outer AA line to outer edge, shift is 0.
121 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
122 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
123 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
124 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
125 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
126 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
127 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
128 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
129
130 // Draw the stroke, from outer edge to inner edge, shift is 8.
131 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
132 1 + 8, 5 + 8, 9 + 8,
133 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
134 6 + 8, 2 + 8, 10 + 8,
135 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
136 3 + 8, 7 + 8, 11 + 8,
137 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
138 4 + 8, 0 + 8, 8 + 8,
139
140 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
141 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
142 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
143 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
144 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
145};
146
joshualitt5ead6da2014-10-22 16:00:29 -0700147static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
148static const int kVertsPerBevelStrokeRect = 24;
149static const int kNumBevelStrokeRectsInIndexBuffer = 256;
150
joshualittb44293e2014-10-28 08:12:18 -0700151static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000152 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
153 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000154}
155
joshualittb44293e2014-10-28 08:12:18 -0700156GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000157 if (miterStroke) {
158 if (NULL == fAAMiterStrokeRectIndexBuffer) {
159 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700160 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
161 kIndicesPerMiterStrokeRect,
162 kNumMiterStrokeRectsInIndexBuffer,
163 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000164 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000165 return fAAMiterStrokeRectIndexBuffer;
166 } else {
167 if (NULL == fAABevelStrokeRectIndexBuffer) {
168 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700169 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
170 kIndicesPerBevelStrokeRect,
171 kNumBevelStrokeRectsInIndexBuffer,
172 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000173 }
174 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000175 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000176}
177
joshualittb44293e2014-10-28 08:12:18 -0700178void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000179 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000180 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700181 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000182 GrDrawState* drawState = target->drawState();
183
bsalomon9c0822a2014-08-11 11:07:48 -0700184 GrColor color = drawState->getColor();
185
bsalomonc30aaa02014-08-13 07:15:29 -0700186 CoverageAttribType covAttribType = set_rect_attribs(drawState);
187 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700188 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
189 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000190
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000191 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000192 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700193 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000194 return;
195 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000196
joshualitt5ead6da2014-10-22 16:00:29 -0700197 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700198 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
199 kIndicesPerAAFillRect,
200 kNumAAFillRectsInIndexBuffer,
201 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700202 }
203 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000204 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700205 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000206 return;
207 }
208
209 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700210 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000211
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000212 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700213 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000214
robertphillips@google.com908aed82013-05-28 13:16:20 +0000215 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
216 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
217
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000218 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000219 // Temporarily #if'ed out. We don't want to pass in the devRect but
220 // right now it is computed in GrContext::apply_aa_to_rect and we don't
221 // want to throw away the work
222#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000223 SkRect devRect;
224 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000225#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000226
egdaniel7b3d5ee2014-08-28 05:41:14 -0700227 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
228 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000229 } else {
230 // compute transformed (1, 0) and (0, 1) vectors
231 SkVector vec[2] = {
232 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
233 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
234 };
235
236 vec[0].normalize();
237 vec[0].scale(SK_ScalarHalf);
238 vec[1].normalize();
239 vec[1].scale(SK_ScalarHalf);
240
robertphillips@google.com91b71162013-05-10 14:09:54 +0000241 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000242 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700243 rect.fRight, rect.fBottom, vstride);
244 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000245
robertphillips@google.com91b71162013-05-10 14:09:54 +0000246 // Now create the inset points and then outset the original
247 // rotated points
248
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000249 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700250 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
251 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
252 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000253 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700254 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
255 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
256 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000257 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700258 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
259 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
260 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000261 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700262 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
263 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
264 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000265 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000266
bsalomon9c0822a2014-08-11 11:07:48 -0700267 // 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 +0000268 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000269 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700270 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700271 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800272 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700273 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700274 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700275 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000276 }
277
robertphillips@google.com908aed82013-05-28 13:16:20 +0000278 int scale;
279 if (inset < SK_ScalarHalf) {
280 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
281 SkASSERT(scale >= 0 && scale <= 255);
282 } else {
283 scale = 0xff;
284 }
285
egdaniel7b3d5ee2014-08-28 05:41:14 -0700286 verts += 4 * vstride;
egdaniele27065a2014-11-06 08:00:48 -0800287
288 float innerCoverage = GrNormalizeByteToFloat(scale);
289 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
290
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000291 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700292 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700293 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800294 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700295 } else {
egdaniele27065a2014-11-06 08:00:48 -0800296 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700297 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000298 }
299
300 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000301 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
302 kVertsPerAAFillRect,
303 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000304 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000305}
306
joshualittb44293e2014-10-28 08:12:18 -0700307void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000308 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000309 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000310 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700311 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000312 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700313 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000314 if (width > 0) {
315 devStrokeSize.set(width, width);
316 combinedMatrix.mapVectors(&devStrokeSize, 1);
317 devStrokeSize.setAbs(devStrokeSize);
318 } else {
319 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
320 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000321
robertphillips@google.com18136d12013-05-10 11:05:58 +0000322 const SkScalar dx = devStrokeSize.fX;
323 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000324 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
325 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000326
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000327 // Temporarily #if'ed out. We don't want to pass in the devRect but
328 // right now it is computed in GrContext::apply_aa_to_rect and we don't
329 // want to throw away the work
330#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000331 SkRect devRect;
332 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000333#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000334
bsalomon@google.com81712882012-11-01 17:12:34 +0000335 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000336 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000337 SkScalar w = devRect.width() - dx;
338 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000339 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000340 }
341
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000342 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000343 devOutside.outset(rx, ry);
344
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000345 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700346 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000347 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700348 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
349 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000350 miterStroke = false;
351 }
352
353 if (spare <= 0 && miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700354 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000355 return;
356 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000357
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000358 SkRect devInside(devRect);
359 devInside.inset(rx, ry);
360
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000361 SkRect devOutsideAssist(devRect);
362
363 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
364 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000365 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000366 if (!miterStroke) {
367 devOutside.inset(0, ry);
368 devOutsideAssist.outset(0, ry);
369 }
370
joshualittb44293e2014-10-28 08:12:18 -0700371 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000372}
373
joshualittb44293e2014-10-28 08:12:18 -0700374void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000375 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000376 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000377 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000378 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000379 GrDrawState* drawState = target->drawState();
380
bsalomonc30aaa02014-08-13 07:15:29 -0700381 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700382
383 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700384 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700385 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
386 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000387
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000388 int innerVertexNum = 4;
389 int outerVertexNum = miterStroke ? 4 : 8;
390 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
391
392 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000393 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700394 SkDebugf("Failed to get space for vertices!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000395 return;
396 }
joshualittb44293e2014-10-28 08:12:18 -0700397 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000398 if (NULL == indexBuffer) {
tfarina38406c82014-10-31 07:11:12 -0700399 SkDebugf("Failed to create index buffer!\n");
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000400 return;
401 }
402
403 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700404 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000405
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000406 // We create vertices for four nested rectangles. There are two ramps from 0 to full
407 // coverage, one on the exterior of the stroke and the other on the interior.
408 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000409 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700410 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
411 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
412 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000413
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000414#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000415 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700416 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000417 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
418 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
419 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000420 if (miterStroke) {
421 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
422 } else {
423 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
424 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000425 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000426#else
427 SkScalar inset = SK_ScalarHalf;
428#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000429
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000430 if (miterStroke) {
431 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700432 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000433 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700434 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
435 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000436 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700437 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000438 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700439 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
440 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000441 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700442 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
443 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000444 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700445 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
446 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000447 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700448 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000449 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700450 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000451 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000452
bsalomon9c0822a2014-08-11 11:07:48 -0700453 // 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 +0000454 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000455 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000456 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700457 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700458 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800459 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700460 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700461 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700462 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463 }
464
bsalomon9c0822a2014-08-11 11:07:48 -0700465 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000466 int scale;
467 if (inset < SK_ScalarHalf) {
468 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
469 SkASSERT(scale >= 0 && scale <= 255);
470 } else {
471 scale = 0xff;
472 }
473
egdaniele27065a2014-11-06 08:00:48 -0800474 float innerCoverage = GrNormalizeByteToFloat(scale);
475 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700476
egdaniele27065a2014-11-06 08:00:48 -0800477 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000478 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700479 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700480 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800481 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700482 } else {
egdaniele27065a2014-11-06 08:00:48 -0800483 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700484 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000485 }
486
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000487 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700488 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000489 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700490 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700491 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
492 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700493 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700494 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700495 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000496 }
497
498 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700499 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
joshualittb44293e2014-10-28 08:12:18 -0700500 totalVertexNum, aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700501 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000502}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000503
joshualittb44293e2014-10-28 08:12:18 -0700504void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000505 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700506 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000507 SkASSERT(combinedMatrix.rectStaysRect());
508 SkASSERT(!rects[1].isEmpty());
509
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000510 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000511 combinedMatrix.mapRect(&devOutside, rects[0]);
512 // can't call mapRect for devInside since it calls sort
513 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
514
515 if (devInside.isEmpty()) {
joshualittb44293e2014-10-28 08:12:18 -0700516 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000517 return;
518 }
519
joshualittb44293e2014-10-28 08:12:18 -0700520 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000521}