blob: 07e81ecef7b9fe7f8a2d380b5c5fca34710207ac [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"
robertphillips@google.com908aed82013-05-28 13:16:20 +000013#include "SkColorPriv.h"
joshualitt5478d422014-11-14 16:00:38 -080014#include "gl/GrGLProcessor.h"
15#include "gl/GrGLGeometryProcessor.h"
16#include "gl/builders/GrGLProgramBuilder.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 {
bsalomonc30aaa02014-08-13 07:15:29 -070021// Should the coverage be multiplied into the color attrib or use a separate attrib.
22enum CoverageAttribType {
23 kUseColor_CoverageAttribType,
24 kUseCoverage_CoverageAttribType,
25};
26}
27
joshualitt56995b52014-12-11 15:44:02 -080028static const GrGeometryProcessor* create_rect_gp(const GrDrawState& drawState, GrColor color,
29 CoverageAttribType* type) {
joshualitt2dd1ae02014-12-03 06:24:10 -080030 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType;
joshualitt56995b52014-12-11 15:44:02 -080031 const GrGeometryProcessor* gp;
32 if (drawState.canTweakAlphaForCoverage()) {
33 gp = GrDefaultGeoProcFactory::Create(color, flags);
34 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr));
35 *type = kUseColor_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070036 } else {
joshualitt2dd1ae02014-12-03 06:24:10 -080037 flags |= GrDefaultGeoProcFactory::kCoverage_GPType;
joshualitt56995b52014-12-11 15:44:02 -080038 gp = GrDefaultGeoProcFactory::Create(color, flags, GrColorIsOpaque(color));
39 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::PositionColorCoverageAttr));
40 *type = kUseCoverage_CoverageAttribType;
bsalomonc30aaa02014-08-13 07:15:29 -070041 }
joshualitt56995b52014-12-11 15:44:02 -080042 return gp;
bsalomonc30aaa02014-08-13 07:15:29 -070043}
44
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000045static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +000046 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000047 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
48 r.fRight - dx, r.fBottom - dy, stride);
49}
50
robertphillips@google.comf6747b02012-06-12 00:32:28 +000051void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000052 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000053 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
54 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000055}
56
robertphillips@google.com6d067302012-12-18 21:47:47 +000057static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000058 0, 1, 5, 5, 4, 0,
59 1, 2, 6, 6, 5, 1,
60 2, 3, 7, 7, 6, 2,
61 3, 0, 4, 4, 7, 3,
62 4, 5, 6, 6, 7, 4,
63};
64
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000065static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +000066static const int kVertsPerAAFillRect = 8;
67static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000068
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000069static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000070 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
71 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
72 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
73 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
74
75 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
76 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
77 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
78 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
79
80 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
81 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
82 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
83 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
84};
85
joshualitt5ead6da2014-10-22 16:00:29 -070086static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
87static const int kVertsPerMiterStrokeRect = 16;
88static const int kNumMiterStrokeRectsInIndexBuffer = 256;
89
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +000090/**
91 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
92 * from the first index. The index layout:
93 * outer AA line: 0~3, 4~7
94 * outer edge: 8~11, 12~15
95 * inner edge: 16~19
96 * inner AA line: 20~23
97 * Following comes a bevel-stroke rect and its indices:
98 *
99 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000100 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000101 * * ______________________________ *
102 * * / 12 15 \ *
103 * * / \ *
104 * 0 * |8 16_____________________19 11 | * 3
105 * * | | | | *
106 * * | | **************** | | *
107 * * | | * 20 23 * | | *
108 * * | | * * | | *
109 * * | | * 21 22 * | | *
110 * * | | **************** | | *
111 * * | |____________________| | *
112 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000113 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000114 * * \13 __________________________14/ *
115 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000116 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000117 * 5 6
118 */
119static const uint16_t gBevelStrokeAARectIdx[] = {
120 // Draw outer AA, from outer AA line to outer edge, shift is 0.
121 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
122 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
123 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
124 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
125 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
126 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
127 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
128 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
129
130 // Draw the stroke, from outer edge to inner edge, shift is 8.
131 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
132 1 + 8, 5 + 8, 9 + 8,
133 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
134 6 + 8, 2 + 8, 10 + 8,
135 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
136 3 + 8, 7 + 8, 11 + 8,
137 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
138 4 + 8, 0 + 8, 8 + 8,
139
140 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
141 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
142 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
143 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
144 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
145};
146
joshualitt5ead6da2014-10-22 16:00:29 -0700147static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
148static const int kVertsPerBevelStrokeRect = 24;
149static const int kNumBevelStrokeRectsInIndexBuffer = 256;
150
joshualittb44293e2014-10-28 08:12:18 -0700151static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000152 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
153 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000154}
155
joshualittb44293e2014-10-28 08:12:18 -0700156GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000157 if (miterStroke) {
158 if (NULL == fAAMiterStrokeRectIndexBuffer) {
159 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700160 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
161 kIndicesPerMiterStrokeRect,
162 kNumMiterStrokeRectsInIndexBuffer,
163 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000164 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000165 return fAAMiterStrokeRectIndexBuffer;
166 } else {
167 if (NULL == fAABevelStrokeRectIndexBuffer) {
168 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700169 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
170 kIndicesPerBevelStrokeRect,
171 kNumBevelStrokeRectsInIndexBuffer,
172 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000173 }
174 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000175 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000176}
177
joshualittb44293e2014-10-28 08:12:18 -0700178void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800179 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800180 GrColor color,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000181 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000182 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700183 const SkRect& devRect) {
joshualitt5478d422014-11-14 16:00:38 -0800184 GrDrawState::AutoRestoreEffects are(drawState);
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000185
joshualitt56995b52014-12-11 15:44:02 -0800186 CoverageAttribType type;
187 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000188
joshualitt56995b52014-12-11 15:44:02 -0800189 size_t vertexStride = gp->getVertexStride();
190 GrDrawTarget::AutoReleaseGeometry geo(target, 8, vertexStride, 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());
209
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000210 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
joshualitt56995b52014-12-11 15:44:02 -0800211 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000212
robertphillips@google.com908aed82013-05-28 13:16:20 +0000213 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
214 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
215
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000216 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000217 // Temporarily #if'ed out. We don't want to pass in the devRect but
218 // right now it is computed in GrContext::apply_aa_to_rect and we don't
219 // want to throw away the work
220#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000221 SkRect devRect;
222 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000223#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000224
joshualitt56995b52014-12-11 15:44:02 -0800225 set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
226 set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000227 } else {
228 // compute transformed (1, 0) and (0, 1) vectors
229 SkVector vec[2] = {
230 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
231 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
232 };
233
234 vec[0].normalize();
235 vec[0].scale(SK_ScalarHalf);
236 vec[1].normalize();
237 vec[1].scale(SK_ScalarHalf);
238
robertphillips@google.com91b71162013-05-10 14:09:54 +0000239 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000240 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
joshualitt56995b52014-12-11 15:44:02 -0800241 rect.fRight, rect.fBottom, vertexStride);
242 combinedMatrix.mapPointsWithStride(fan0Pos, vertexStride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000243
robertphillips@google.com91b71162013-05-10 14:09:54 +0000244 // Now create the inset points and then outset the original
245 // rotated points
246
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000247 // TL
joshualitt56995b52014-12-11 15:44:02 -0800248 *((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
249 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
250 *((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000251 // BL
joshualitt56995b52014-12-11 15:44:02 -0800252 *((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
253 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
254 *((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000255 // BR
joshualitt56995b52014-12-11 15:44:02 -0800256 *((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
257 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
258 *((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000259 // TR
joshualitt56995b52014-12-11 15:44:02 -0800260 *((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
261 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
262 *((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000263 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000264
bsalomon9c0822a2014-08-11 11:07:48 -0700265 // 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 +0000266 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267 for (int i = 0; i < 4; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800268 if (kUseCoverage_CoverageAttribType == type) {
269 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
270 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700271 } else {
joshualitt56995b52014-12-11 15:44:02 -0800272 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700273 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000274 }
275
robertphillips@google.com908aed82013-05-28 13:16:20 +0000276 int scale;
277 if (inset < SK_ScalarHalf) {
278 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
279 SkASSERT(scale >= 0 && scale <= 255);
280 } else {
281 scale = 0xff;
282 }
283
joshualitt56995b52014-12-11 15:44:02 -0800284 verts += 4 * vertexStride;
egdaniele27065a2014-11-06 08:00:48 -0800285
286 float innerCoverage = GrNormalizeByteToFloat(scale);
287 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
288
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000289 for (int i = 0; i < 4; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800290 if (kUseCoverage_CoverageAttribType == type) {
291 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
292 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700293 } else {
joshualitt56995b52014-12-11 15:44:02 -0800294 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700295 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296 }
297
298 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800299 target->drawIndexedInstances(drawState,
joshualitt56995b52014-12-11 15:44:02 -0800300 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800301 kTriangles_GrPrimitiveType,
302 1,
robertphillips@google.com6d067302012-12-18 21:47:47 +0000303 kVertsPerAAFillRect,
304 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000305 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000306}
307
joshualittb44293e2014-10-28 08:12:18 -0700308void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800309 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800310 GrColor color,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000311 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000312 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000313 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700314 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000315 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700316 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000317 if (width > 0) {
318 devStrokeSize.set(width, width);
319 combinedMatrix.mapVectors(&devStrokeSize, 1);
320 devStrokeSize.setAbs(devStrokeSize);
321 } else {
322 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
323 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000324
robertphillips@google.com18136d12013-05-10 11:05:58 +0000325 const SkScalar dx = devStrokeSize.fX;
326 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000327 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
328 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000329
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000330 // Temporarily #if'ed out. We don't want to pass in the devRect but
331 // right now it is computed in GrContext::apply_aa_to_rect and we don't
332 // want to throw away the work
333#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000334 SkRect devRect;
335 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000336#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000337
bsalomon@google.com81712882012-11-01 17:12:34 +0000338 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000339 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000340 SkScalar w = devRect.width() - dx;
341 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000342 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000343 }
344
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000345 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000346 devOutside.outset(rx, ry);
347
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000348 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700349 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000350 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700351 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
352 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000353 miterStroke = false;
354 }
355
356 if (spare <= 0 && miterStroke) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800357 this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000358 return;
359 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000360
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000361 SkRect devInside(devRect);
362 devInside.inset(rx, ry);
363
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000364 SkRect devOutsideAssist(devRect);
365
366 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
367 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000368 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000369 if (!miterStroke) {
370 devOutside.inset(0, ry);
371 devOutsideAssist.outset(0, ry);
372 }
373
joshualitt2e3b3e32014-12-09 13:31:14 -0800374 this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
joshualitt9853cce2014-11-17 14:22:48 -0800375 miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000376}
377
joshualittb44293e2014-10-28 08:12:18 -0700378void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800379 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800380 GrColor color,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000381 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000382 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000383 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000384 bool miterStroke) {
joshualitt5478d422014-11-14 16:00:38 -0800385 GrDrawState::AutoRestoreEffects are(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700386
joshualitt56995b52014-12-11 15:44:02 -0800387 CoverageAttribType type;
388 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*drawState, color, &type));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000389
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000390 int innerVertexNum = 4;
391 int outerVertexNum = miterStroke ? 4 : 8;
392 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
393
joshualitt56995b52014-12-11 15:44:02 -0800394 size_t vstride = gp->getVertexStride();
joshualitt2dd1ae02014-12-03 06:24:10 -0800395 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 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());
407
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000408 // We create vertices for four nested rectangles. There are two ramps from 0 to full
409 // coverage, one on the exterior of the stroke and the other on the interior.
410 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000411 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700412 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
413 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
414 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000415
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000416#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000417 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700418 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000419 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
420 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
421 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000422 if (miterStroke) {
423 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
424 } else {
425 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
426 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000427 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000428#else
429 SkScalar inset = SK_ScalarHalf;
430#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000431
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000432 if (miterStroke) {
433 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700434 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000435 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700436 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
437 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000438 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700439 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000440 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700441 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
442 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000443 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700444 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
445 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000446 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700447 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
448 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000449 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700450 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000451 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700452 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000453 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000454
bsalomon9c0822a2014-08-11 11:07:48 -0700455 // 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 +0000456 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000457 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000458 for (int i = 0; i < outerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800459 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700460 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800461 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700462 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700463 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700464 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000465 }
466
bsalomon9c0822a2014-08-11 11:07:48 -0700467 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000468 int scale;
469 if (inset < SK_ScalarHalf) {
470 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
471 SkASSERT(scale >= 0 && scale <= 255);
472 } else {
473 scale = 0xff;
474 }
475
egdaniele27065a2014-11-06 08:00:48 -0800476 float innerCoverage = GrNormalizeByteToFloat(scale);
477 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
bsalomonc30aaa02014-08-13 07:15:29 -0700478
egdaniele27065a2014-11-06 08:00:48 -0800479 verts += outerVertexNum * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000480 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800481 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700482 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
egdaniele27065a2014-11-06 08:00:48 -0800483 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700484 } else {
egdaniele27065a2014-11-06 08:00:48 -0800485 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor;
bsalomonc30aaa02014-08-13 07:15:29 -0700486 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000487 }
488
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000489 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700490 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000491 for (int i = 0; i < innerVertexNum; ++i) {
joshualitt56995b52014-12-11 15:44:02 -0800492 if (kUseCoverage_CoverageAttribType == type) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700493 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
494 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700495 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700496 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700497 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000498 }
499
500 target->setIndexSourceToBuffer(indexBuffer);
joshualitt9853cce2014-11-17 14:22:48 -0800501 target->drawIndexedInstances(drawState,
joshualitt56995b52014-12-11 15:44:02 -0800502 gp,
joshualitt9853cce2014-11-17 14:22:48 -0800503 kTriangles_GrPrimitiveType,
504 1,
505 totalVertexNum,
506 aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700507 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000508}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000509
joshualittb44293e2014-10-28 08:12:18 -0700510void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
joshualitt9853cce2014-11-17 14:22:48 -0800511 GrDrawState* drawState,
joshualitt2e3b3e32014-12-09 13:31:14 -0800512 GrColor color,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000513 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700514 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000515 SkASSERT(combinedMatrix.rectStaysRect());
516 SkASSERT(!rects[1].isEmpty());
517
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000518 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000519 combinedMatrix.mapRect(&devOutside, rects[0]);
520 // can't call mapRect for devInside since it calls sort
521 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
522
523 if (devInside.isEmpty()) {
joshualitt2e3b3e32014-12-09 13:31:14 -0800524 this->fillAARect(target, drawState, color, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000525 return;
526 }
527
joshualitt2e3b3e32014-12-09 13:31:14 -0800528 this->geometryStrokeAARect(target, drawState, color, devOutside, devOutsideAssist, devInside,
529 true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000530}