blob: 9384457a1ed9c94499e9f3b5839ae720481bd1c1 [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
joshualitt30ba4362014-08-21 20:18:45 -07008#include "gl/builders/GrGLProgramBuilder.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +00009#include "GrAARectRenderer.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000010#include "GrGpu.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000011#include "gl/GrGLEffect.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
joshualitt30ba4362014-08-21 20:18:45 -070047 virtual void emitCode(GrGLFullProgramBuilder* 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
joshualitt30ba4362014-08-21 20:18:45 -070060 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
61 const SkString* attr0Name =
62 vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
63 vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
64
65 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000066 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt30ba4362014-08-21 20:18:45 -070067 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
68 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
69 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000070 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
71 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -070072 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
73 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000074 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
75 // value of coverage that is used. In other words it is the coverage that is
76 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -070077 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
78 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000079
80 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -070081 fsBuilder->codeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000082 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
83 fsRectName);
84 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -070085 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000086 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
87 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000088
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000089
joshualitt30ba4362014-08-21 20:18:45 -070090 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +000091 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000092 }
93
bsalomon63e99f72014-07-21 08:03:14 -070094 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000095
kkinnunen7510b222014-07-30 00:04:16 -070096 virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000097
98 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000099 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000100 };
101
102
103private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000104 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000105 this->addVertexAttrib(kVec4f_GrSLType);
106 }
107
108 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
109
110 GR_DECLARE_EFFECT_TEST;
111
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000112 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000113};
114
115
116GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
117
bsalomon83d081a2014-07-08 09:56:10 -0700118GrEffect* GrAlignedRectEffect::TestCreate(SkRandom* random,
119 GrContext* context,
120 const GrDrawTargetCaps&,
121 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000122 return GrAlignedRectEffect::Create();
123}
124
125///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000126class GrGLRectEffect;
127
128/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000129 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000130 * for an arbitrarily oriented rect. The rect is specified as:
131 * Center of the rect
132 * Unit vector point down the height of the rect
133 * Half width + 0.5
134 * Half height + 0.5
135 * The center and vector are stored in a vec4 varying ("RectEdge") with the
136 * center in the xy components and the vector in the zw components.
137 * The munged width and height are stored in a vec2 varying ("WidthHeight")
138 * with the width in x and the height in y.
139 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000140class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000141public:
bsalomon83d081a2014-07-08 09:56:10 -0700142 static GrEffect* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000143 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
144 gRectEffect->ref();
145 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000146 }
147
148 virtual ~GrRectEffect() {}
149
150 static const char* Name() { return "RectEdge"; }
151
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000152 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000153 uint32_t* validFlags) const SK_OVERRIDE {
154 *validFlags = 0;
155 }
156
157 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
158 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
159 }
160
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000161 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000162 public:
163 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
164 : INHERITED (factory) {}
165
joshualitt30ba4362014-08-21 20:18:45 -0700166 virtual void emitCode(GrGLFullProgramBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000167 const GrDrawEffect& drawEffect,
bsalomon63e99f72014-07-21 08:03:14 -0700168 const GrEffectKey& key,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000169 const char* outputColor,
170 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000171 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000172 const TextureSamplerArray& samplers) SK_OVERRIDE {
173 // setup the varying for the center point and the unit vector
174 // that points down the height of the rect
175 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000176 builder->addVarying(kVec4f_GrSLType, "RectEdge",
177 &vsRectEdgeName, &fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700178
179 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000180 const SkString* attr0Name =
joshualitt30ba4362014-08-21 20:18:45 -0700181 vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
182 vsBuilder->codeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000183
184 // setup the varying for width/2+.5 and height/2+.5
185 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000186 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
187 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000188 const SkString* attr1Name =
joshualitt30ba4362014-08-21 20:18:45 -0700189 vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
190 vsBuilder->codeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000191
joshualitt30ba4362014-08-21 20:18:45 -0700192 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000193 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt30ba4362014-08-21 20:18:45 -0700194 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
195 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
196 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000197 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
198 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -0700199 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
200 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000201 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
202 // value of coverage that is used. In other words it is the coverage that is
203 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -0700204 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
205 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000206
207 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -0700208 fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
209 fsBuilder->fragmentPosition(), fsRectEdgeName);
210 fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000211 fsRectEdgeName, fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700212 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000213 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
214 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000215
216 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -0700217 fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000218 fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700219 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000220 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000221 fsWidthHeightName);
222
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000223
joshualitt30ba4362014-08-21 20:18:45 -0700224 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.orga34995e2013-10-23 05:42:03 +0000225 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000226 }
227
bsalomon63e99f72014-07-21 08:03:14 -0700228 static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000229
kkinnunen7510b222014-07-30 00:04:16 -0700230 virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000231
232 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000233 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000234 };
235
236
237private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000238 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000239 this->addVertexAttrib(kVec4f_GrSLType);
240 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000241 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000242 }
243
244 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
245
246 GR_DECLARE_EFFECT_TEST;
247
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000248 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000249};
250
251
252GR_DEFINE_EFFECT_TEST(GrRectEffect);
253
bsalomon83d081a2014-07-08 09:56:10 -0700254GrEffect* GrRectEffect::TestCreate(SkRandom* random,
255 GrContext* context,
256 const GrDrawTargetCaps&,
257 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000258 return GrRectEffect::Create();
259}
260
261///////////////////////////////////////////////////////////////////////////////
262
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000263namespace {
bsalomon9c0822a2014-08-11 11:07:48 -0700264extern const GrVertexAttrib gAARectAttribs[] = {
265 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
266 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
267 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000268};
269
bsalomonc30aaa02014-08-13 07:15:29 -0700270// Should the coverage be multiplied into the color attrib or use a separate attrib.
271enum CoverageAttribType {
272 kUseColor_CoverageAttribType,
273 kUseCoverage_CoverageAttribType,
274};
275}
276
277static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
278 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700279 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700280 return kUseColor_CoverageAttribType;
281 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700282 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + 2 * sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700283 return kUseCoverage_CoverageAttribType;
284 }
285}
286
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000287static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000288 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000289 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
290 r.fRight - dx, r.fBottom - dy, stride);
291}
292
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000293void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000294 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000295 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
296 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000297}
298
robertphillips@google.com6d067302012-12-18 21:47:47 +0000299static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000300 0, 1, 5, 5, 4, 0,
301 1, 2, 6, 6, 5, 1,
302 2, 3, 7, 7, 6, 2,
303 3, 0, 4, 4, 7, 3,
304 4, 5, 6, 6, 7, 4,
305};
306
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000307static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000308static const int kVertsPerAAFillRect = 8;
309static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000310
311GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000312 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
313 sizeof(uint16_t) *
314 kNumAAFillRectsInIndexBuffer;
315
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000316 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000317 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000318 if (NULL != fAAFillRectIndexBuffer) {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000319 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->map();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000320 bool useTempData = (NULL == data);
321 if (useTempData) {
322 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
323 }
324 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
325 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
326 // the inner rect (for AA) and 2 for the inner rect.
327 int baseIdx = i * kIndicesPerAAFillRect;
328 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
329 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
330 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
331 }
332 }
333 if (useTempData) {
334 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000335 SkFAIL("Can't get AA Fill Rect indices into buffer!");
robertphillips@google.com6d067302012-12-18 21:47:47 +0000336 }
337 SkDELETE_ARRAY(data);
338 } else {
commit-bot@chromium.org8341eb72014-05-07 20:51:05 +0000339 fAAFillRectIndexBuffer->unmap();
robertphillips@google.com6d067302012-12-18 21:47:47 +0000340 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000341 }
342 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000343
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000344 return fAAFillRectIndexBuffer;
345}
346
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000347static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000348 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
349 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
350 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
351 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
352
353 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
354 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
355 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
356 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
357
358 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
359 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
360 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
361 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
362};
363
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000364/**
365 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
366 * from the first index. The index layout:
367 * outer AA line: 0~3, 4~7
368 * outer edge: 8~11, 12~15
369 * inner edge: 16~19
370 * inner AA line: 20~23
371 * Following comes a bevel-stroke rect and its indices:
372 *
373 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000374 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000375 * * ______________________________ *
376 * * / 12 15 \ *
377 * * / \ *
378 * 0 * |8 16_____________________19 11 | * 3
379 * * | | | | *
380 * * | | **************** | | *
381 * * | | * 20 23 * | | *
382 * * | | * * | | *
383 * * | | * 21 22 * | | *
384 * * | | **************** | | *
385 * * | |____________________| | *
386 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000387 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000388 * * \13 __________________________14/ *
389 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000390 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000391 * 5 6
392 */
393static const uint16_t gBevelStrokeAARectIdx[] = {
394 // Draw outer AA, from outer AA line to outer edge, shift is 0.
395 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
396 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
397 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
398 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
399 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
400 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
401 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
402 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
403
404 // Draw the stroke, from outer edge to inner edge, shift is 8.
405 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
406 1 + 8, 5 + 8, 9 + 8,
407 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
408 6 + 8, 2 + 8, 10 + 8,
409 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
410 3 + 8, 7 + 8, 11 + 8,
411 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
412 4 + 8, 0 + 8, 8 + 8,
413
414 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
415 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
416 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
417 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
418 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
419};
420
421int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000422 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
423 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000424}
425
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000426GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
427 if (miterStroke) {
428 if (NULL == fAAMiterStrokeRectIndexBuffer) {
429 fAAMiterStrokeRectIndexBuffer =
430 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
431 if (NULL != fAAMiterStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000432#ifdef SK_DEBUG
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000433 bool updated =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434#endif
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000435 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
436 sizeof(gMiterStrokeAARectIdx));
437 GR_DEBUGASSERT(updated);
438 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000439 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000440 return fAAMiterStrokeRectIndexBuffer;
441 } else {
442 if (NULL == fAABevelStrokeRectIndexBuffer) {
443 fAABevelStrokeRectIndexBuffer =
444 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
445 if (NULL != fAABevelStrokeRectIndexBuffer) {
446#ifdef SK_DEBUG
447 bool updated =
448#endif
449 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
450 sizeof(gBevelStrokeAARectIdx));
451 GR_DEBUGASSERT(updated);
452 }
453 }
454 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000455 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000456}
457
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000458void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
459 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000460 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000461 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700462 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000463 GrDrawState* drawState = target->drawState();
464
bsalomon9c0822a2014-08-11 11:07:48 -0700465 GrColor color = drawState->getColor();
466
bsalomonc30aaa02014-08-13 07:15:29 -0700467 CoverageAttribType covAttribType = set_rect_attribs(drawState);
468 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700469 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
470 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000471
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000472 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000473 if (!geo.succeeded()) {
474 GrPrintf("Failed to get space for vertices!\n");
475 return;
476 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000477
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000478 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
479 if (NULL == indexBuffer) {
480 GrPrintf("Failed to create index buffer!\n");
481 return;
482 }
483
484 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700485 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000486
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000487 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700488 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000489
robertphillips@google.com908aed82013-05-28 13:16:20 +0000490 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
491 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
492
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000493 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000494 // Temporarily #if'ed out. We don't want to pass in the devRect but
495 // right now it is computed in GrContext::apply_aa_to_rect and we don't
496 // want to throw away the work
497#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000498 SkRect devRect;
499 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000500#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000501
egdaniel7b3d5ee2014-08-28 05:41:14 -0700502 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
503 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000504 } else {
505 // compute transformed (1, 0) and (0, 1) vectors
506 SkVector vec[2] = {
507 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
508 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
509 };
510
511 vec[0].normalize();
512 vec[0].scale(SK_ScalarHalf);
513 vec[1].normalize();
514 vec[1].scale(SK_ScalarHalf);
515
robertphillips@google.com91b71162013-05-10 14:09:54 +0000516 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000517 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700518 rect.fRight, rect.fBottom, vstride);
519 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000520
robertphillips@google.com91b71162013-05-10 14:09:54 +0000521 // Now create the inset points and then outset the original
522 // rotated points
523
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000524 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700525 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
526 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
527 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000528 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700529 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
530 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
531 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000532 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700533 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
534 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
535 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000536 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700537 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
538 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
539 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000540 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000541
bsalomon9c0822a2014-08-11 11:07:48 -0700542 // 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 +0000543 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000544 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700545 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700546 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
547 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700548 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700549 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700550 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000551 }
552
robertphillips@google.com908aed82013-05-28 13:16:20 +0000553 int scale;
554 if (inset < SK_ScalarHalf) {
555 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
556 SkASSERT(scale >= 0 && scale <= 255);
557 } else {
558 scale = 0xff;
559 }
560
bsalomon9c0822a2014-08-11 11:07:48 -0700561 GrColor innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700562 if (kUseCoverage_CoverageAttribType == covAttribType) {
563 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
564 } else {
565 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
566 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700567 verts += 4 * vstride;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000568 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700569 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700570 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
571 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700572 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700573 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700574 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000575 }
576
577 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000578 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
579 kVertsPerAAFillRect,
580 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000581 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000582}
583
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000584namespace {
585
586// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000587struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000588 SkPoint fPos;
589 SkPoint fCenter;
590 SkPoint fDir;
591 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000592};
593
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000594// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000595extern const GrVertexAttrib gAARectVertexAttribs[] = {
596 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000597 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
598 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kEffect_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000599};
600
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000601// Axis Aligned
602struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000603 SkPoint fPos;
604 SkPoint fOffset;
605 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000606};
607
608// Axis Aligned
609extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
610 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000611 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000612};
613
robertphillips@google.com42903302013-04-20 12:26:07 +0000614};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000615
616void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
617 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000618 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000619 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000620 GrDrawState* drawState = target->drawState();
621
622 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
623 combinedMatrix.mapPoints(&center, 1);
624
625 // compute transformed (0, 1) vector
626 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
627 dir.normalize();
628
629 // compute transformed (width, 0) and (0, height) vectors
630 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000631 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
632 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000633 };
634
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000635 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
636 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700637 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
638 sizeof(RectVertex));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000639
640 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
641 if (!geo.succeeded()) {
642 GrPrintf("Failed to get space for vertices!\n");
643 return;
644 }
645
646 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
647
bsalomon83d081a2014-07-08 09:56:10 -0700648 GrEffect* effect = GrRectEffect::Create();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000649 static const int kRectAttrIndex = 1;
650 static const int kWidthIndex = 2;
joshualittbd769d02014-09-04 08:56:46 -0700651 drawState->setGeometryProcessor(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000652
653 for (int i = 0; i < 4; ++i) {
654 verts[i].fCenter = center;
655 verts[i].fDir = dir;
656 verts[i].fWidthHeight.fX = newWidth;
657 verts[i].fWidthHeight.fY = newHeight;
658 }
659
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000660 SkRect devRect;
661 combinedMatrix.mapRect(&devRect, rect);
662
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000663 SkRect devBounds = {
664 devRect.fLeft - SK_ScalarHalf,
665 devRect.fTop - SK_ScalarHalf,
666 devRect.fRight + SK_ScalarHalf,
667 devRect.fBottom + SK_ScalarHalf
668 };
669
670 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
671 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
672 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
673 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
674
675 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
676 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
677 target->resetIndexSource();
678}
679
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000680void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
681 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000682 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000683 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000684 GrDrawState* drawState = target->drawState();
685 SkASSERT(combinedMatrix.rectStaysRect());
686
egdaniel7b3d5ee2014-08-28 05:41:14 -0700687 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
688 sizeof(AARectVertex));
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000689
690 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
691 if (!geo.succeeded()) {
692 GrPrintf("Failed to get space for vertices!\n");
693 return;
694 }
695
696 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
697
bsalomon83d081a2014-07-08 09:56:10 -0700698 GrEffect* effect = GrAlignedRectEffect::Create();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000699 static const int kOffsetIndex = 1;
joshualittbd769d02014-09-04 08:56:46 -0700700 drawState->setGeometryProcessor(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000701
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000702 SkRect devRect;
703 combinedMatrix.mapRect(&devRect, rect);
704
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000705 SkRect devBounds = {
706 devRect.fLeft - SK_ScalarHalf,
707 devRect.fTop - SK_ScalarHalf,
708 devRect.fRight + SK_ScalarHalf,
709 devRect.fBottom + SK_ScalarHalf
710 };
711
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000712 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000713 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
714 SkScalarHalf(devRect.height()) + SK_ScalarHalf
715 };
716
717 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
718 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
719 verts[0].fWidthHeight = widthHeight;
720
721 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
722 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
723 verts[1].fWidthHeight = widthHeight;
724
725 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
726 verts[2].fOffset = widthHeight;
727 verts[2].fWidthHeight = widthHeight;
728
729 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
730 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
731 verts[3].fWidthHeight = widthHeight;
732
733 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
734 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
735 target->resetIndexSource();
736}
737
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000738void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000739 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000740 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000741 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000742 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700743 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000744 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700745 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000746 if (width > 0) {
747 devStrokeSize.set(width, width);
748 combinedMatrix.mapVectors(&devStrokeSize, 1);
749 devStrokeSize.setAbs(devStrokeSize);
750 } else {
751 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
752 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000753
robertphillips@google.com18136d12013-05-10 11:05:58 +0000754 const SkScalar dx = devStrokeSize.fX;
755 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000756 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
757 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000758
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000759 // Temporarily #if'ed out. We don't want to pass in the devRect but
760 // right now it is computed in GrContext::apply_aa_to_rect and we don't
761 // want to throw away the work
762#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000763 SkRect devRect;
764 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000765#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000766
bsalomon@google.com81712882012-11-01 17:12:34 +0000767 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000768 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000769 SkScalar w = devRect.width() - dx;
770 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000771 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000772 }
773
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000774 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000775 devOutside.outset(rx, ry);
776
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000777 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700778 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000779 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700780 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
781 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000782 miterStroke = false;
783 }
784
785 if (spare <= 0 && miterStroke) {
bsalomon9c0822a2014-08-11 11:07:48 -0700786 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000787 return;
788 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000789
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000790 SkRect devInside(devRect);
791 devInside.inset(rx, ry);
792
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000793 SkRect devOutsideAssist(devRect);
794
795 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
796 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000797 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000798 if (!miterStroke) {
799 devOutside.inset(0, ry);
800 devOutsideAssist.outset(0, ry);
801 }
802
bsalomon9c0822a2014-08-11 11:07:48 -0700803 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000804}
805
806void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
807 GrDrawTarget* target,
808 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000809 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000810 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000811 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000812 GrDrawState* drawState = target->drawState();
813
bsalomonc30aaa02014-08-13 07:15:29 -0700814 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700815
816 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700817 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700818 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
819 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000820
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000821 int innerVertexNum = 4;
822 int outerVertexNum = miterStroke ? 4 : 8;
823 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
824
825 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000826 if (!geo.succeeded()) {
827 GrPrintf("Failed to get space for vertices!\n");
828 return;
829 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000830 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000831 if (NULL == indexBuffer) {
832 GrPrintf("Failed to create index buffer!\n");
833 return;
834 }
835
836 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700837 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000838
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000839 // We create vertices for four nested rectangles. There are two ramps from 0 to full
840 // coverage, one on the exterior of the stroke and the other on the interior.
841 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000842 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700843 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
844 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
845 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000846
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000847#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000848 // TODO: this only really works if the X & Y margins are the same all around
849 // the rect
850 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
851 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
852 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000853 if (miterStroke) {
854 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
855 } else {
856 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
857 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000858 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000859#else
860 SkScalar inset = SK_ScalarHalf;
861#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000862
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000863 if (miterStroke) {
864 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700865 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000866 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700867 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
868 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000869 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700870 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000871 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700872 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
873 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000874 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700875 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
876 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000877 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700878 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
879 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000880 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700881 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000882 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700883 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000884 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000885
bsalomon9c0822a2014-08-11 11:07:48 -0700886 // 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 +0000887 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000888 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000889 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700890 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700891 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
892 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700893 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700894 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700895 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000896 }
897
bsalomon9c0822a2014-08-11 11:07:48 -0700898 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000899 int scale;
900 if (inset < SK_ScalarHalf) {
901 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
902 SkASSERT(scale >= 0 && scale <= 255);
903 } else {
904 scale = 0xff;
905 }
906
egdaniel7b3d5ee2014-08-28 05:41:14 -0700907 verts += outerVertexNum * vstride;
bsalomonc30aaa02014-08-13 07:15:29 -0700908 GrColor innerCoverage;
909 if (kUseCoverage_CoverageAttribType == covAttribType) {
910 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
911 } else {
912 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
913 }
914
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000915 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700916 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700917 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
918 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700919 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700920 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700921 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000922 }
923
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000924 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700925 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000926 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700927 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700928 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
929 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700930 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700931 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700932 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000933 }
934
935 target->setIndexSourceToBuffer(indexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000936 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
937 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000938}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000939
940void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
941 GrDrawTarget* target,
942 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700943 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000944 SkASSERT(combinedMatrix.rectStaysRect());
945 SkASSERT(!rects[1].isEmpty());
946
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000947 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000948 combinedMatrix.mapRect(&devOutside, rects[0]);
949 // can't call mapRect for devInside since it calls sort
950 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
951
952 if (devInside.isEmpty()) {
bsalomon9c0822a2014-08-11 11:07:48 -0700953 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000954 return;
955 }
956
bsalomon9c0822a2014-08-11 11:07:48 -0700957 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000958}