blob: 59e9b6f810d70b565057c82e8caf8daab4c2b0c4 [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"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000010#include "gl/GrGLEffect.h"
bsalomon848faf02014-07-11 10:01:02 -070011#include "gl/GrGLShaderBuilder.h"
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000012#include "gl/GrGLVertexEffect.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000013#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000015#include "effects/GrVertexEffect.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000016
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000017///////////////////////////////////////////////////////////////////////////////
18class GrGLAlignedRectEffect;
19
20// Axis Aligned special case
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000021class GrAlignedRectEffect : public GrVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000022public:
bsalomon83d081a2014-07-08 09:56:10 -070023 static GrEffect* Create() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000024 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
25 gAlignedRectEffect->ref();
26 return gAlignedRectEffect;
27 }
28
29 virtual ~GrAlignedRectEffect() {}
30
31 static const char* Name() { return "AlignedRectEdge"; }
32
33 virtual void getConstantColorComponents(GrColor* color,
34 uint32_t* validFlags) const SK_OVERRIDE {
35 *validFlags = 0;
36 }
37
38 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
39 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
40 }
41
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000042 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000043 public:
44 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
45 : INHERITED (factory) {}
46
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000047 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000048 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -070049 const GrEffectKey& key,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000050 const char* outputColor,
51 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +000052 const TransformedCoordsArray&,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000053 const TextureSamplerArray& samplers) SK_OVERRIDE {
54 // setup the varying for the Axis aligned rect effect
55 // xy -> interpolated offset
56 // zw -> w/2+0.5, h/2+0.5
57 const char *vsRectName, *fsRectName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000058 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000059 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000060 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
61 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000062
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000063 // TODO: compute all these offsets, spans, and scales in the VS
64 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
65 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
66 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
67 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
68 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
69 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
70 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
71 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
72 // value of coverage that is used. In other words it is the coverage that is
73 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000074 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
75 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000076
77 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000078 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000079 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
80 fsRectName);
81 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000082 builder->fsCodeAppendf(
83 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
84 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000085
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000086
87 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000088 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000089 }
90
bsalomon63e99f72014-07-21 08:03:14 -070091 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000092
93 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
94
95 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000096 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000097 };
98
99
100private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000101 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000102 this->addVertexAttrib(kVec4f_GrSLType);
103 }
104
105 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
106
107 GR_DECLARE_EFFECT_TEST;
108
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000109 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000110};
111
112
113GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
114
bsalomon83d081a2014-07-08 09:56:10 -0700115GrEffect* GrAlignedRectEffect::TestCreate(SkRandom* random,
116 GrContext* context,
117 const GrDrawTargetCaps&,
118 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000119 return GrAlignedRectEffect::Create();
120}
121
122///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000123class GrGLRectEffect;
124
125/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000126 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000127 * for an arbitrarily oriented rect. The rect is specified as:
128 * Center of the rect
129 * Unit vector point down the height of the rect
130 * Half width + 0.5
131 * Half height + 0.5
132 * The center and vector are stored in a vec4 varying ("RectEdge") with the
133 * center in the xy components and the vector in the zw components.
134 * The munged width and height are stored in a vec2 varying ("WidthHeight")
135 * with the width in x and the height in y.
136 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000137class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000138public:
bsalomon83d081a2014-07-08 09:56:10 -0700139 static GrEffect* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000140 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
141 gRectEffect->ref();
142 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000143 }
144
145 virtual ~GrRectEffect() {}
146
147 static const char* Name() { return "RectEdge"; }
148
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000149 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000150 uint32_t* validFlags) const SK_OVERRIDE {
151 *validFlags = 0;
152 }
153
154 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
155 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
156 }
157
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000158 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000159 public:
160 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
161 : INHERITED (factory) {}
162
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000163 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000164 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -0700165 const GrEffectKey& key,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000166 const char* outputColor,
167 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000168 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000169 const TextureSamplerArray& samplers) SK_OVERRIDE {
170 // setup the varying for the center point and the unit vector
171 // that points down the height of the rect
172 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000173 builder->addVarying(kVec4f_GrSLType, "RectEdge",
174 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000175 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000176 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
177 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000178
179 // setup the varying for width/2+.5 and height/2+.5
180 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000181 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
182 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000183 const SkString* attr1Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000184 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
185 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000186
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000187 // TODO: compute all these offsets, spans, and scales in the VS
188 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
189 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
190 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
191 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
192 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
193 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
194 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
195 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
196 // value of coverage that is used. In other words it is the coverage that is
197 // used in the interior of the rect after the ramp.
198 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
199 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000200
201 // Compute the coverage for the rect's width
bsalomon22900002014-06-24 11:16:52 -0700202 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203 builder->fragmentPosition(), fsRectEdgeName);
204 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
205 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000206 builder->fsCodeAppendf(
207 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
208 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000209
210 // Compute the coverage for the rect's height and merge with the width
211 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
212 fsRectEdgeName);
213 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000214 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000215 fsWidthHeightName);
216
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000217
218 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000219 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000220 }
221
bsalomon63e99f72014-07-21 08:03:14 -0700222 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000223
224 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
225
226 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000227 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000228 };
229
230
231private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000232 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000233 this->addVertexAttrib(kVec4f_GrSLType);
234 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000235 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000236 }
237
238 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
239
240 GR_DECLARE_EFFECT_TEST;
241
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000242 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000243};
244
245
246GR_DEFINE_EFFECT_TEST(GrRectEffect);
247
bsalomon83d081a2014-07-08 09:56:10 -0700248GrEffect* GrRectEffect::TestCreate(SkRandom* random,
249 GrContext* context,
250 const GrDrawTargetCaps&,
251 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000252 return GrRectEffect::Create();
253}
254
255///////////////////////////////////////////////////////////////////////////////
256
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000257namespace {
258
robertphillips@google.com42903302013-04-20 12:26:07 +0000259extern const GrVertexAttrib gAARectCoverageAttribs[] = {
260 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000261 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000262};
263
264extern const GrVertexAttrib gAARectColorAttribs[] = {
265 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000266 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000267};
268
269static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
270 if (useCoverage) {
271 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
272 } else {
273 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
274 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000275}
276
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000277static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000278 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000279 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
280 r.fRight - dx, r.fBottom - dy, stride);
281}
282
283};
284
285void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000286 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000287 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
288 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000289}
290
robertphillips@google.com6d067302012-12-18 21:47:47 +0000291static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000292 0, 1, 5, 5, 4, 0,
293 1, 2, 6, 6, 5, 1,
294 2, 3, 7, 7, 6, 2,
295 3, 0, 4, 4, 7, 3,
296 4, 5, 6, 6, 7, 4,
297};
298
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000299static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000300static const int kVertsPerAAFillRect = 8;
301static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000302
303GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000304 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
305 sizeof(uint16_t) *
306 kNumAAFillRectsInIndexBuffer;
307
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000308 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000309 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000310 if (NULL != fAAFillRectIndexBuffer) {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000311 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000312 bool useTempData = (NULL == data);
313 if (useTempData) {
314 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
315 }
316 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
317 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
318 // the inner rect (for AA) and 2 for the inner rect.
319 int baseIdx = i * kIndicesPerAAFillRect;
320 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
321 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
322 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
323 }
324 }
325 if (useTempData) {
326 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000327 SkFAIL("Can't get AA Fill Rect indices into buffer!");
robertphillips@google.com6d067302012-12-18 21:47:47 +0000328 }
329 SkDELETE_ARRAY(data);
330 } else {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000331 fAAFillRectIndexBuffer->unmap();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000332 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000333 }
334 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000335
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000336 return fAAFillRectIndexBuffer;
337}
338
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000339static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000340 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
341 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
342 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
343 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
344
345 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
346 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
347 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
348 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
349
350 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
351 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
352 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
353 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
354};
355
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000356/**
357 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
358 * from the first index. The index layout:
359 * outer AA line: 0~3, 4~7
360 * outer edge: 8~11, 12~15
361 * inner edge: 16~19
362 * inner AA line: 20~23
363 * Following comes a bevel-stroke rect and its indices:
364 *
365 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000366 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000367 * * ______________________________ *
368 * * / 12 15 \ *
369 * * / \ *
370 * 0 * |8 16_____________________19 11 | * 3
371 * * | | | | *
372 * * | | **************** | | *
373 * * | | * 20 23 * | | *
374 * * | | * * | | *
375 * * | | * 21 22 * | | *
376 * * | | **************** | | *
377 * * | |____________________| | *
378 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000379 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000380 * * \13 __________________________14/ *
381 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000382 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000383 * 5 6
384 */
385static const uint16_t gBevelStrokeAARectIdx[] = {
386 // Draw outer AA, from outer AA line to outer edge, shift is 0.
387 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
388 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
389 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
390 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
391 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
392 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
393 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
394 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
395
396 // Draw the stroke, from outer edge to inner edge, shift is 8.
397 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
398 1 + 8, 5 + 8, 9 + 8,
399 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
400 6 + 8, 2 + 8, 10 + 8,
401 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
402 3 + 8, 7 + 8, 11 + 8,
403 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
404 4 + 8, 0 + 8, 8 + 8,
405
406 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
407 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
408 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
409 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
410 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
411};
412
413int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000414 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
415 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000416}
417
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000418GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
419 if (miterStroke) {
420 if (NULL == fAAMiterStrokeRectIndexBuffer) {
421 fAAMiterStrokeRectIndexBuffer =
422 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
423 if (NULL != fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000424#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000425 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000426#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000427 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
428 sizeof(gMiterStrokeAARectIdx));
429 GR_DEBUGASSERT(updated);
430 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000431 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000432 return fAAMiterStrokeRectIndexBuffer;
433 } else {
434 if (NULL == fAABevelStrokeRectIndexBuffer) {
435 fAABevelStrokeRectIndexBuffer =
436 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
437 if (NULL != fAABevelStrokeRectIndexBuffer) {
438#ifdef SK_DEBUG
439 bool updated =
440#endif
441 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
442 sizeof(gBevelStrokeAARectIdx));
443 GR_DEBUGASSERT(updated);
444 }
445 }
446 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000447 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000448}
449
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000450void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
451 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000452 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000453 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000454 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000455 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000456 GrDrawState* drawState = target->drawState();
457
robertphillips@google.com42903302013-04-20 12:26:07 +0000458 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000459
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000460 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000461 if (!geo.succeeded()) {
462 GrPrintf("Failed to get space for vertices!\n");
463 return;
464 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000465
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000466 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
467 if (NULL == indexBuffer) {
468 GrPrintf("Failed to create index buffer!\n");
469 return;
470 }
471
472 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000473 size_t vsize = drawState->getVertexSize();
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000474 SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000475
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000476 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
477 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000478
robertphillips@google.com908aed82013-05-28 13:16:20 +0000479 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
480 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
481
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000482 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000483 // Temporarily #if'ed out. We don't want to pass in the devRect but
484 // right now it is computed in GrContext::apply_aa_to_rect and we don't
485 // want to throw away the work
486#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000487 SkRect devRect;
488 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000489#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000490
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000491 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000492 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000493 } else {
494 // compute transformed (1, 0) and (0, 1) vectors
495 SkVector vec[2] = {
496 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
497 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
498 };
499
500 vec[0].normalize();
501 vec[0].scale(SK_ScalarHalf);
502 vec[1].normalize();
503 vec[1].scale(SK_ScalarHalf);
504
robertphillips@google.com91b71162013-05-10 14:09:54 +0000505 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000506 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
507 rect.fRight, rect.fBottom, vsize);
508 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
509
robertphillips@google.com91b71162013-05-10 14:09:54 +0000510 // Now create the inset points and then outset the original
511 // rotated points
512
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000513 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000514 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000515 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
516 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
517 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000518 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000519 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
520 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
521 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000522 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000523 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
524 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
525 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000526 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000527 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
528 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
529 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000530
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000531 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000532 for (int i = 0; i < 4; ++i) {
533 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
534 }
535
robertphillips@google.com908aed82013-05-28 13:16:20 +0000536 int scale;
537 if (inset < SK_ScalarHalf) {
538 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
539 SkASSERT(scale >= 0 && scale <= 255);
540 } else {
541 scale = 0xff;
542 }
543
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000544 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000545 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000546 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000547 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000548 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000549 innerColor = target->getDrawState().getColor();
550 } else {
551 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
552 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000553 }
554
555 verts += 4 * vsize;
556 for (int i = 0; i < 4; ++i) {
557 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
558 }
559
560 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000561 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
562 kVertsPerAAFillRect,
563 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000564 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000565}
566
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000567namespace {
568
569// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000570struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000571 SkPoint fPos;
572 SkPoint fCenter;
573 SkPoint fDir;
574 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000575};
576
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000577// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000578extern const GrVertexAttrib gAARectVertexAttribs[] = {
579 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000580 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
581 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000582};
583
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000584// Axis Aligned
585struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000586 SkPoint fPos;
587 SkPoint fOffset;
588 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000589};
590
591// Axis Aligned
592extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
593 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000594 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000595};
596
robertphillips@google.com42903302013-04-20 12:26:07 +0000597};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000598
599void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
600 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000601 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000602 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000603 GrDrawState* drawState = target->drawState();
604
605 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
606 combinedMatrix.mapPoints(&center, 1);
607
608 // compute transformed (0, 1) vector
609 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
610 dir.normalize();
611
612 // compute transformed (width, 0) and (0, height) vectors
613 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000614 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
615 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000616 };
617
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000618 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
619 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000620 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000621 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000622
623 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
624 if (!geo.succeeded()) {
625 GrPrintf("Failed to get space for vertices!\n");
626 return;
627 }
628
629 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
630
bsalomon83d081a2014-07-08 09:56:10 -0700631 GrEffect* effect = GrRectEffect::Create();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000632 static const int kRectAttrIndex = 1;
633 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000634 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000635
636 for (int i = 0; i < 4; ++i) {
637 verts[i].fCenter = center;
638 verts[i].fDir = dir;
639 verts[i].fWidthHeight.fX = newWidth;
640 verts[i].fWidthHeight.fY = newHeight;
641 }
642
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000643 SkRect devRect;
644 combinedMatrix.mapRect(&devRect, rect);
645
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000646 SkRect devBounds = {
647 devRect.fLeft - SK_ScalarHalf,
648 devRect.fTop - SK_ScalarHalf,
649 devRect.fRight + SK_ScalarHalf,
650 devRect.fBottom + SK_ScalarHalf
651 };
652
653 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
654 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
655 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
656 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
657
658 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
659 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
660 target->resetIndexSource();
661}
662
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000663void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
664 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000665 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000666 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000667 GrDrawState* drawState = target->drawState();
668 SkASSERT(combinedMatrix.rectStaysRect());
669
670 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000671 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000672
673 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
674 if (!geo.succeeded()) {
675 GrPrintf("Failed to get space for vertices!\n");
676 return;
677 }
678
679 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
680
bsalomon83d081a2014-07-08 09:56:10 -0700681 GrEffect* effect = GrAlignedRectEffect::Create();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000682 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000683 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000684
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000685 SkRect devRect;
686 combinedMatrix.mapRect(&devRect, rect);
687
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000688 SkRect devBounds = {
689 devRect.fLeft - SK_ScalarHalf,
690 devRect.fTop - SK_ScalarHalf,
691 devRect.fRight + SK_ScalarHalf,
692 devRect.fBottom + SK_ScalarHalf
693 };
694
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000695 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000696 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
697 SkScalarHalf(devRect.height()) + SK_ScalarHalf
698 };
699
700 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
701 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
702 verts[0].fWidthHeight = widthHeight;
703
704 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
705 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
706 verts[1].fWidthHeight = widthHeight;
707
708 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
709 verts[2].fOffset = widthHeight;
710 verts[2].fWidthHeight = widthHeight;
711
712 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
713 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
714 verts[3].fWidthHeight = widthHeight;
715
716 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
717 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
718 target->resetIndexSource();
719}
720
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000721void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000722 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000723 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000724 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000725 const SkRect& devRect,
egdanield58a0ba2014-06-11 10:30:05 -0700726 const SkStrokeRec& stroke,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000727 bool useVertexCoverage) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000728 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700729 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000730 if (width > 0) {
731 devStrokeSize.set(width, width);
732 combinedMatrix.mapVectors(&devStrokeSize, 1);
733 devStrokeSize.setAbs(devStrokeSize);
734 } else {
735 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
736 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000737
robertphillips@google.com18136d12013-05-10 11:05:58 +0000738 const SkScalar dx = devStrokeSize.fX;
739 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000740 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
741 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000742
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000743 // Temporarily #if'ed out. We don't want to pass in the devRect but
744 // right now it is computed in GrContext::apply_aa_to_rect and we don't
745 // want to throw away the work
746#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000747 SkRect devRect;
748 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000749#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000750
bsalomon@google.com81712882012-11-01 17:12:34 +0000751 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000752 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000753 SkScalar w = devRect.width() - dx;
754 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000755 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000756 }
757
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000758 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000759 devOutside.outset(rx, ry);
760
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000761 bool miterStroke = true;
762 // small miter limit means right angles show bevel...
egdanield58a0ba2014-06-11 10:30:05 -0700763 if (stroke.getJoin() != SkPaint::kMiter_Join || stroke.getMiter() < SK_ScalarSqrt2) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000764 miterStroke = false;
765 }
766
767 if (spare <= 0 && miterStroke) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000768 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000769 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000770 return;
771 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000772
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000773 SkRect devInside(devRect);
774 devInside.inset(rx, ry);
775
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000776 SkRect devOutsideAssist(devRect);
777
778 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
779 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000780 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000781 if (!miterStroke) {
782 devOutside.inset(0, ry);
783 devOutsideAssist.outset(0, ry);
784 }
785
786 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
787 devInside, useVertexCoverage, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000788}
789
790void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
791 GrDrawTarget* target,
792 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000793 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000794 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000795 bool useVertexCoverage,
796 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000797 GrDrawState* drawState = target->drawState();
798
robertphillips@google.com42903302013-04-20 12:26:07 +0000799 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000800
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000801 int innerVertexNum = 4;
802 int outerVertexNum = miterStroke ? 4 : 8;
803 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
804
805 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000806 if (!geo.succeeded()) {
807 GrPrintf("Failed to get space for vertices!\n");
808 return;
809 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000810 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000811 if (NULL == indexBuffer) {
812 GrPrintf("Failed to create index buffer!\n");
813 return;
814 }
815
816 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000817 size_t vsize = drawState->getVertexSize();
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000818 SkASSERT(sizeof(SkPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000819
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000820 // We create vertices for four nested rectangles. There are two ramps from 0 to full
821 // coverage, one on the exterior of the stroke and the other on the interior.
822 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000823 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
824 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vsize);
825 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vsize);
826 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000827
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000828#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000829 // TODO: this only really works if the X & Y margins are the same all around
830 // the rect
831 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
832 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
833 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000834 if (miterStroke) {
835 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
836 } else {
837 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
838 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000839 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000840#else
841 SkScalar inset = SK_ScalarHalf;
842#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000843
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000844 if (miterStroke) {
845 // outermost
846 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
847 // inner two
848 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
849 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
850 // innermost
851 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
852 } else {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000853 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vsize);
854 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vsize);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000855 // outermost
856 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
857 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
858 // outer one of the inner two
859 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
860 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
861 // inner one of the inner two
862 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
863 // innermost
864 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
865 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000866
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000867 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000868 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000869 for (int i = 0; i < outerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000870 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
871 }
872
robertphillips@google.com353f0972013-06-28 17:57:06 +0000873 int scale;
874 if (inset < SK_ScalarHalf) {
875 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
876 SkASSERT(scale >= 0 && scale <= 255);
877 } else {
878 scale = 0xff;
879 }
880
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000881 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000882 GrColor innerColor;
883 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000884 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000885 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000886 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000887 innerColor = target->getDrawState().getColor();
888 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000889 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
890 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000891 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000892
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000893 verts += outerVertexNum * vsize;
894 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000895 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
896 }
897
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000898 // The innermost rect has 0 coverage
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000899 verts += (outerVertexNum + innerVertexNum) * vsize;
900 for (int i = 0; i < innerVertexNum; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000901 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
902 }
903
904 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000905 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
906 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000907}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000908
909void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
910 GrDrawTarget* target,
911 const SkRect rects[2],
912 const SkMatrix& combinedMatrix,
913 bool useVertexCoverage) {
914 SkASSERT(combinedMatrix.rectStaysRect());
915 SkASSERT(!rects[1].isEmpty());
916
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000917 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000918 combinedMatrix.mapRect(&devOutside, rects[0]);
919 // can't call mapRect for devInside since it calls sort
920 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
921
922 if (devInside.isEmpty()) {
923 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
924 return;
925 }
926
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000927 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
928 devInside, useVertexCoverage, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000929}