blob: e5d1593bc060e06e751a9ec27d1acc5c1f305b26 [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAARectRenderer.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +00009#include "GrGpu.h"
joshualitt47bb3822014-10-07 16:43:25 -070010#include "gl/builders/GrGLProgramBuilder.h"
joshualittb0a8a372014-09-23 09:50:21 -070011#include "gl/GrGLProcessor.h"
joshualitt249af152014-09-15 11:41:13 -070012#include "gl/GrGLGeometryProcessor.h"
joshualittb0a8a372014-09-23 09:50:21 -070013#include "GrTBackendProcessorFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000014#include "SkColorPriv.h"
joshualittb0a8a372014-09-23 09:50:21 -070015#include "GrGeometryProcessor.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000016
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000017///////////////////////////////////////////////////////////////////////////////
18class GrGLAlignedRectEffect;
19
20// Axis Aligned special case
joshualitt249af152014-09-15 11:41:13 -070021class GrAlignedRectEffect : public GrGeometryProcessor {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000022public:
joshualittb0a8a372014-09-23 09:50:21 -070023 static GrGeometryProcessor* Create() {
bsalomon98b33eb2014-10-15 11:05:26 -070024 GR_CREATE_STATIC_PROCESSOR(gAlignedRectEffect, GrAlignedRectEffect, ());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000025 gAlignedRectEffect->ref();
26 return gAlignedRectEffect;
27 }
28
29 virtual ~GrAlignedRectEffect() {}
30
31 static const char* Name() { return "AlignedRectEdge"; }
32
joshualitt249af152014-09-15 11:41:13 -070033 const GrShaderVar& inRect() const { return fInRect; }
34
joshualittb0a8a372014-09-23 09:50:21 -070035 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
36 return GrTBackendGeometryProcessorFactory<GrAlignedRectEffect>::getInstance();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000037 }
38
joshualittb0a8a372014-09-23 09:50:21 -070039 class GLProcessor : public GrGLGeometryProcessor {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000040 public:
joshualittb0a8a372014-09-23 09:50:21 -070041 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000042 : INHERITED (factory) {}
43
joshualittc369e7c2014-10-22 10:56:26 -070044 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000045 // setup the varying for the Axis aligned rect effect
46 // xy -> interpolated offset
47 // zw -> w/2+0.5, h/2+0.5
48 const char *vsRectName, *fsRectName;
joshualittc369e7c2014-10-22 10:56:26 -070049 args.fPB->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000050
joshualittc369e7c2014-10-22 10:56:26 -070051 const GrShaderVar& inRect = args.fGP.cast<GrAlignedRectEffect>().inRect();
52 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt249af152014-09-15 11:41:13 -070053 vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, inRect.c_str());
joshualitt30ba4362014-08-21 20:18:45 -070054
joshualittc369e7c2014-10-22 10:56:26 -070055 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000056 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt30ba4362014-08-21 20:18:45 -070057 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
58 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
59 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000060 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
61 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -070062 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
63 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000064 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
65 // value of coverage that is used. In other words it is the coverage that is
66 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -070067 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
68 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000069
70 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -070071 fsBuilder->codeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000072 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
73 fsRectName);
74 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -070075 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000076 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
77 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000078
commit-bot@chromium.org824c3462013-10-10 06:30:18 +000079
joshualittc369e7c2014-10-22 10:56:26 -070080 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
81 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000082 }
83
joshualittb0a8a372014-09-23 09:50:21 -070084 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000085
joshualittb0a8a372014-09-23 09:50:21 -070086 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000087
88 private:
joshualitt249af152014-09-15 11:41:13 -070089 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000090 };
91
92
93private:
joshualitt249af152014-09-15 11:41:13 -070094 GrAlignedRectEffect()
95 : fInRect(this->addVertexAttrib(GrShaderVar("inRect",
96 kVec4f_GrSLType,
97 GrShaderVar::kAttribute_TypeModifier))) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000098 }
99
joshualitt249af152014-09-15 11:41:13 -0700100 const GrShaderVar& fInRect;
101
bsalomon0e08fc12014-10-15 08:19:04 -0700102 virtual bool onIsEqual(const GrGeometryProcessor&) const SK_OVERRIDE { return true; }
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000103
egdaniel1a8ecdf2014-10-03 06:24:12 -0700104 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
egdanielccb2e382014-10-13 12:53:46 -0700105 inout->mulByUnknownAlpha();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700106 }
107
joshualittb0a8a372014-09-23 09:50:21 -0700108 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000109
joshualitt249af152014-09-15 11:41:13 -0700110 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000111};
112
113
joshualittb0a8a372014-09-23 09:50:21 -0700114GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrAlignedRectEffect);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000115
joshualittb0a8a372014-09-23 09:50:21 -0700116GrGeometryProcessor* GrAlignedRectEffect::TestCreate(SkRandom* random,
117 GrContext* context,
118 const GrDrawTargetCaps&,
119 GrTexture* textures[]) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000120 return GrAlignedRectEffect::Create();
121}
122
123///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000124class GrGLRectEffect;
125
126/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000127 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000128 * for an arbitrarily oriented rect. The rect is specified as:
129 * Center of the rect
130 * Unit vector point down the height of the rect
131 * Half width + 0.5
132 * Half height + 0.5
133 * The center and vector are stored in a vec4 varying ("RectEdge") with the
134 * center in the xy components and the vector in the zw components.
135 * The munged width and height are stored in a vec2 varying ("WidthHeight")
136 * with the width in x and the height in y.
137 */
joshualitt249af152014-09-15 11:41:13 -0700138
139class GrRectEffect : public GrGeometryProcessor {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000140public:
joshualittb0a8a372014-09-23 09:50:21 -0700141 static GrGeometryProcessor* Create() {
bsalomon98b33eb2014-10-15 11:05:26 -0700142 GR_CREATE_STATIC_PROCESSOR(gRectEffect, GrRectEffect, ());
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000143 gRectEffect->ref();
144 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000145 }
146
147 virtual ~GrRectEffect() {}
148
149 static const char* Name() { return "RectEdge"; }
150
joshualitt249af152014-09-15 11:41:13 -0700151 const GrShaderVar& inRectEdge() const { return fInRectEdge; }
152 const GrShaderVar& inWidthHeight() const { return fInWidthHeight; }
153
joshualittb0a8a372014-09-23 09:50:21 -0700154 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
155 return GrTBackendGeometryProcessorFactory<GrRectEffect>::getInstance();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000156 }
157
joshualittb0a8a372014-09-23 09:50:21 -0700158 class GLProcessor : public GrGLGeometryProcessor {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000159 public:
joshualittb0a8a372014-09-23 09:50:21 -0700160 GLProcessor(const GrBackendProcessorFactory& factory, const GrProcessor&)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000161 : INHERITED (factory) {}
162
joshualittc369e7c2014-10-22 10:56:26 -0700163 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000164 // setup the varying for the center point and the unit vector
165 // that points down the height of the rect
166 const char *vsRectEdgeName, *fsRectEdgeName;
joshualittc369e7c2014-10-22 10:56:26 -0700167 args.fPB->addVarying(kVec4f_GrSLType, "RectEdge",
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000168 &vsRectEdgeName, &fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700169
joshualittc369e7c2014-10-22 10:56:26 -0700170 const GrRectEffect& rectEffect = args.fGP.cast<GrRectEffect>();
171 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt249af152014-09-15 11:41:13 -0700172 vsBuilder->codeAppendf("%s = %s;", vsRectEdgeName, rectEffect.inRectEdge().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000173
174 // setup the varying for width/2+.5 and height/2+.5
175 const char *vsWidthHeightName, *fsWidthHeightName;
joshualittc369e7c2014-10-22 10:56:26 -0700176 args.fPB->addVarying(kVec2f_GrSLType, "WidthHeight",
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000177 &vsWidthHeightName, &fsWidthHeightName);
joshualitt249af152014-09-15 11:41:13 -0700178 vsBuilder->codeAppendf("%s = %s;",
179 vsWidthHeightName,
180 rectEffect.inWidthHeight().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000181
joshualittc369e7c2014-10-22 10:56:26 -0700182 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000183 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt30ba4362014-08-21 20:18:45 -0700184 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
185 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
186 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000187 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
188 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -0700189 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
190 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000191 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
192 // value of coverage that is used. In other words it is the coverage that is
193 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -0700194 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
195 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000196
197 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -0700198 fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
199 fsBuilder->fragmentPosition(), fsRectEdgeName);
200 fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000201 fsRectEdgeName, fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700202 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000203 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
204 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000205
206 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -0700207 fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000208 fsRectEdgeName);
joshualitt30ba4362014-08-21 20:18:45 -0700209 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000210 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000211 fsWidthHeightName);
212
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000213
joshualittc369e7c2014-10-22 10:56:26 -0700214 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
215 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000216 }
217
joshualittb0a8a372014-09-23 09:50:21 -0700218 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000219
joshualittb0a8a372014-09-23 09:50:21 -0700220 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000221
222 private:
joshualitt249af152014-09-15 11:41:13 -0700223 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000224 };
225
226
joshualitt249af152014-09-15 11:41:13 -0700227
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000228private:
joshualitt249af152014-09-15 11:41:13 -0700229 GrRectEffect()
230 : fInRectEdge(this->addVertexAttrib(GrShaderVar("inRectEdge",
231 kVec4f_GrSLType,
232 GrShaderVar::kAttribute_TypeModifier)))
233 , fInWidthHeight(this->addVertexAttrib(
234 GrShaderVar("inWidthHeight",
235 kVec2f_GrSLType,
236 GrShaderVar::kAttribute_TypeModifier))) {
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000237 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000238 }
239
bsalomon0e08fc12014-10-15 08:19:04 -0700240 virtual bool onIsEqual(const GrGeometryProcessor&) const SK_OVERRIDE { return true; }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000241
egdaniel1a8ecdf2014-10-03 06:24:12 -0700242 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
egdanielccb2e382014-10-13 12:53:46 -0700243 inout->mulByUnknownAlpha();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700244 }
245
joshualitt249af152014-09-15 11:41:13 -0700246 const GrShaderVar& fInRectEdge;
247 const GrShaderVar& fInWidthHeight;
248
joshualittb0a8a372014-09-23 09:50:21 -0700249 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000250
joshualitt249af152014-09-15 11:41:13 -0700251 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000252};
253
254
joshualittb0a8a372014-09-23 09:50:21 -0700255GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrRectEffect);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000256
joshualittb0a8a372014-09-23 09:50:21 -0700257GrGeometryProcessor* GrRectEffect::TestCreate(SkRandom* random,
258 GrContext* context,
259 const GrDrawTargetCaps&,
260 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000261 return GrRectEffect::Create();
262}
263
264///////////////////////////////////////////////////////////////////////////////
265
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000266namespace {
bsalomon9c0822a2014-08-11 11:07:48 -0700267extern const GrVertexAttrib gAARectAttribs[] = {
268 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
269 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
270 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000271};
272
bsalomonc30aaa02014-08-13 07:15:29 -0700273// Should the coverage be multiplied into the color attrib or use a separate attrib.
274enum CoverageAttribType {
275 kUseColor_CoverageAttribType,
276 kUseCoverage_CoverageAttribType,
277};
278}
279
280static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
281 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700282 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700283 return kUseColor_CoverageAttribType;
284 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700285 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + 2 * sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700286 return kUseCoverage_CoverageAttribType;
287 }
288}
289
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000290static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000291 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000292 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
293 r.fRight - dx, r.fBottom - dy, stride);
294}
295
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000297 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000298 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
299 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000300}
301
robertphillips@google.com6d067302012-12-18 21:47:47 +0000302static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000303 0, 1, 5, 5, 4, 0,
304 1, 2, 6, 6, 5, 1,
305 2, 3, 7, 7, 6, 2,
306 3, 0, 4, 4, 7, 3,
307 4, 5, 6, 6, 7, 4,
308};
309
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000310static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000311static const int kVertsPerAAFillRect = 8;
312static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000313
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000314static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000315 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
316 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
317 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
318 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
319
320 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
321 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
322 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
323 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
324
325 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
326 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
327 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
328 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
329};
330
joshualitt5ead6da2014-10-22 16:00:29 -0700331static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
332static const int kVertsPerMiterStrokeRect = 16;
333static const int kNumMiterStrokeRectsInIndexBuffer = 256;
334
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000335/**
336 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
337 * from the first index. The index layout:
338 * outer AA line: 0~3, 4~7
339 * outer edge: 8~11, 12~15
340 * inner edge: 16~19
341 * inner AA line: 20~23
342 * Following comes a bevel-stroke rect and its indices:
343 *
344 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000345 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000346 * * ______________________________ *
347 * * / 12 15 \ *
348 * * / \ *
349 * 0 * |8 16_____________________19 11 | * 3
350 * * | | | | *
351 * * | | **************** | | *
352 * * | | * 20 23 * | | *
353 * * | | * * | | *
354 * * | | * 21 22 * | | *
355 * * | | **************** | | *
356 * * | |____________________| | *
357 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000358 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000359 * * \13 __________________________14/ *
360 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000361 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000362 * 5 6
363 */
364static const uint16_t gBevelStrokeAARectIdx[] = {
365 // Draw outer AA, from outer AA line to outer edge, shift is 0.
366 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
367 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
368 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
369 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
370 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
371 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
372 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
373 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
374
375 // Draw the stroke, from outer edge to inner edge, shift is 8.
376 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
377 1 + 8, 5 + 8, 9 + 8,
378 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
379 6 + 8, 2 + 8, 10 + 8,
380 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
381 3 + 8, 7 + 8, 11 + 8,
382 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
383 4 + 8, 0 + 8, 8 + 8,
384
385 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
386 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
387 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
388 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
389 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
390};
391
joshualitt5ead6da2014-10-22 16:00:29 -0700392static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
393static const int kVertsPerBevelStrokeRect = 24;
394static const int kNumBevelStrokeRectsInIndexBuffer = 256;
395
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000396int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000397 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
398 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000399}
400
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000401GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
402 if (miterStroke) {
403 if (NULL == fAAMiterStrokeRectIndexBuffer) {
404 fAAMiterStrokeRectIndexBuffer =
joshualitt5ead6da2014-10-22 16:00:29 -0700405 gpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
406 kIndicesPerMiterStrokeRect,
407 kNumMiterStrokeRectsInIndexBuffer,
408 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000409 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000410 return fAAMiterStrokeRectIndexBuffer;
411 } else {
412 if (NULL == fAABevelStrokeRectIndexBuffer) {
413 fAABevelStrokeRectIndexBuffer =
joshualitt5ead6da2014-10-22 16:00:29 -0700414 gpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
415 kIndicesPerBevelStrokeRect,
416 kNumBevelStrokeRectsInIndexBuffer,
417 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000418 }
419 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000420 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000421}
422
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000423void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
424 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000425 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000426 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700427 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000428 GrDrawState* drawState = target->drawState();
429
bsalomon9c0822a2014-08-11 11:07:48 -0700430 GrColor color = drawState->getColor();
431
bsalomonc30aaa02014-08-13 07:15:29 -0700432 CoverageAttribType covAttribType = set_rect_attribs(drawState);
433 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700434 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
435 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000436
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000437 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000438 if (!geo.succeeded()) {
439 GrPrintf("Failed to get space for vertices!\n");
440 return;
441 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000442
joshualitt5ead6da2014-10-22 16:00:29 -0700443 if (NULL == fAAFillRectIndexBuffer) {
444 fAAFillRectIndexBuffer = gpu->createInstancedIndexBuffer(gFillAARectIdx,
445 kIndicesPerAAFillRect,
446 kNumAAFillRectsInIndexBuffer,
447 kVertsPerAAFillRect);
448 }
449 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000450 if (NULL == indexBuffer) {
451 GrPrintf("Failed to create index buffer!\n");
452 return;
453 }
454
455 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700456 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000457
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000458 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700459 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000460
robertphillips@google.com908aed82013-05-28 13:16:20 +0000461 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
462 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
463
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000464 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000465 // Temporarily #if'ed out. We don't want to pass in the devRect but
466 // right now it is computed in GrContext::apply_aa_to_rect and we don't
467 // want to throw away the work
468#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000469 SkRect devRect;
470 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000471#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000472
egdaniel7b3d5ee2014-08-28 05:41:14 -0700473 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
474 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000475 } else {
476 // compute transformed (1, 0) and (0, 1) vectors
477 SkVector vec[2] = {
478 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
479 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
480 };
481
482 vec[0].normalize();
483 vec[0].scale(SK_ScalarHalf);
484 vec[1].normalize();
485 vec[1].scale(SK_ScalarHalf);
486
robertphillips@google.com91b71162013-05-10 14:09:54 +0000487 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000488 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700489 rect.fRight, rect.fBottom, vstride);
490 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000491
robertphillips@google.com91b71162013-05-10 14:09:54 +0000492 // Now create the inset points and then outset the original
493 // rotated points
494
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000495 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700496 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
497 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
498 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000499 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700500 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
501 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
502 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000503 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700504 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
505 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
506 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000507 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700508 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
509 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
510 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000511 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000512
bsalomon9c0822a2014-08-11 11:07:48 -0700513 // 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 +0000514 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000515 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700516 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700517 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
518 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700519 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700520 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700521 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000522 }
523
robertphillips@google.com908aed82013-05-28 13:16:20 +0000524 int scale;
525 if (inset < SK_ScalarHalf) {
526 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
527 SkASSERT(scale >= 0 && scale <= 255);
528 } else {
529 scale = 0xff;
530 }
531
bsalomon9c0822a2014-08-11 11:07:48 -0700532 GrColor innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700533 if (kUseCoverage_CoverageAttribType == covAttribType) {
534 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
535 } else {
536 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
537 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700538 verts += 4 * vstride;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000539 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700540 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700541 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
542 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700543 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700544 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700545 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000546 }
547
548 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000549 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
550 kVertsPerAAFillRect,
551 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000552 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000553}
554
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000555namespace {
556
557// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000558struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000559 SkPoint fPos;
560 SkPoint fCenter;
561 SkPoint fDir;
562 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000563};
564
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000565// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000566extern const GrVertexAttrib gAARectVertexAttribs[] = {
567 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700568 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
569 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000570};
571
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000572// Axis Aligned
573struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000574 SkPoint fPos;
575 SkPoint fOffset;
576 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000577};
578
579// Axis Aligned
580extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
581 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700582 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000583};
584
robertphillips@google.com42903302013-04-20 12:26:07 +0000585};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000586
587void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
588 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000589 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000590 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000591 GrDrawState* drawState = target->drawState();
592
593 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
594 combinedMatrix.mapPoints(&center, 1);
595
596 // compute transformed (0, 1) vector
597 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
598 dir.normalize();
599
600 // compute transformed (width, 0) and (0, height) vectors
601 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000602 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
603 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000604 };
605
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000606 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
607 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700608 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
609 sizeof(RectVertex));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000610
611 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
612 if (!geo.succeeded()) {
613 GrPrintf("Failed to get space for vertices!\n");
614 return;
615 }
616
617 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
618
joshualittb0a8a372014-09-23 09:50:21 -0700619 GrGeometryProcessor* gp = GrRectEffect::Create();
620 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000621
622 for (int i = 0; i < 4; ++i) {
623 verts[i].fCenter = center;
624 verts[i].fDir = dir;
625 verts[i].fWidthHeight.fX = newWidth;
626 verts[i].fWidthHeight.fY = newHeight;
627 }
628
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000629 SkRect devRect;
630 combinedMatrix.mapRect(&devRect, rect);
631
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000632 SkRect devBounds = {
633 devRect.fLeft - SK_ScalarHalf,
634 devRect.fTop - SK_ScalarHalf,
635 devRect.fRight + SK_ScalarHalf,
636 devRect.fBottom + SK_ScalarHalf
637 };
638
639 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
640 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
641 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
642 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
643
644 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
645 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
646 target->resetIndexSource();
647}
648
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000649void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
650 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000651 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000652 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000653 GrDrawState* drawState = target->drawState();
654 SkASSERT(combinedMatrix.rectStaysRect());
655
egdaniel7b3d5ee2014-08-28 05:41:14 -0700656 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
657 sizeof(AARectVertex));
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000658
659 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
660 if (!geo.succeeded()) {
661 GrPrintf("Failed to get space for vertices!\n");
662 return;
663 }
664
665 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
666
joshualittb0a8a372014-09-23 09:50:21 -0700667 GrGeometryProcessor* gp = GrAlignedRectEffect::Create();
668 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000669
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000670 SkRect devRect;
671 combinedMatrix.mapRect(&devRect, rect);
672
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000673 SkRect devBounds = {
674 devRect.fLeft - SK_ScalarHalf,
675 devRect.fTop - SK_ScalarHalf,
676 devRect.fRight + SK_ScalarHalf,
677 devRect.fBottom + SK_ScalarHalf
678 };
679
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000680 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000681 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
682 SkScalarHalf(devRect.height()) + SK_ScalarHalf
683 };
684
685 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
686 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
687 verts[0].fWidthHeight = widthHeight;
688
689 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
690 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
691 verts[1].fWidthHeight = widthHeight;
692
693 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
694 verts[2].fOffset = widthHeight;
695 verts[2].fWidthHeight = widthHeight;
696
697 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
698 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
699 verts[3].fWidthHeight = widthHeight;
700
701 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
702 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
703 target->resetIndexSource();
704}
705
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000706void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000707 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000708 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000709 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000710 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700711 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000712 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700713 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000714 if (width > 0) {
715 devStrokeSize.set(width, width);
716 combinedMatrix.mapVectors(&devStrokeSize, 1);
717 devStrokeSize.setAbs(devStrokeSize);
718 } else {
719 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
720 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000721
robertphillips@google.com18136d12013-05-10 11:05:58 +0000722 const SkScalar dx = devStrokeSize.fX;
723 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000724 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
725 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000726
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000727 // Temporarily #if'ed out. We don't want to pass in the devRect but
728 // right now it is computed in GrContext::apply_aa_to_rect and we don't
729 // want to throw away the work
730#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000731 SkRect devRect;
732 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000733#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000734
bsalomon@google.com81712882012-11-01 17:12:34 +0000735 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000736 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000737 SkScalar w = devRect.width() - dx;
738 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000739 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000740 }
741
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000742 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000743 devOutside.outset(rx, ry);
744
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000745 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700746 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000747 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700748 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
749 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000750 miterStroke = false;
751 }
752
753 if (spare <= 0 && miterStroke) {
bsalomon9c0822a2014-08-11 11:07:48 -0700754 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000755 return;
756 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000757
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000758 SkRect devInside(devRect);
759 devInside.inset(rx, ry);
760
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000761 SkRect devOutsideAssist(devRect);
762
763 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
764 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000765 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000766 if (!miterStroke) {
767 devOutside.inset(0, ry);
768 devOutsideAssist.outset(0, ry);
769 }
770
bsalomon9c0822a2014-08-11 11:07:48 -0700771 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000772}
773
774void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
775 GrDrawTarget* target,
776 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000777 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000778 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000779 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000780 GrDrawState* drawState = target->drawState();
781
bsalomonc30aaa02014-08-13 07:15:29 -0700782 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700783
784 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700785 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700786 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
787 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000788
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000789 int innerVertexNum = 4;
790 int outerVertexNum = miterStroke ? 4 : 8;
791 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
792
793 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000794 if (!geo.succeeded()) {
795 GrPrintf("Failed to get space for vertices!\n");
796 return;
797 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000798 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000799 if (NULL == indexBuffer) {
800 GrPrintf("Failed to create index buffer!\n");
801 return;
802 }
803
804 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700805 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000806
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000807 // We create vertices for four nested rectangles. There are two ramps from 0 to full
808 // coverage, one on the exterior of the stroke and the other on the interior.
809 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000810 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700811 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
812 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
813 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000814
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000815#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000816 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700817 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000818 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
819 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
820 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000821 if (miterStroke) {
822 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
823 } else {
824 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
825 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000826 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000827#else
828 SkScalar inset = SK_ScalarHalf;
829#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000830
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000831 if (miterStroke) {
832 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700833 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000834 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700835 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
836 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000837 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700838 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000839 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700840 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
841 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000842 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700843 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
844 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000845 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700846 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
847 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000848 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700849 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000850 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700851 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000852 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000853
bsalomon9c0822a2014-08-11 11:07:48 -0700854 // 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 +0000855 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000856 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000857 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700858 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700859 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
860 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700861 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700862 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700863 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000864 }
865
bsalomon9c0822a2014-08-11 11:07:48 -0700866 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000867 int scale;
868 if (inset < SK_ScalarHalf) {
869 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
870 SkASSERT(scale >= 0 && scale <= 255);
871 } else {
872 scale = 0xff;
873 }
874
egdaniel7b3d5ee2014-08-28 05:41:14 -0700875 verts += outerVertexNum * vstride;
bsalomonc30aaa02014-08-13 07:15:29 -0700876 GrColor innerCoverage;
877 if (kUseCoverage_CoverageAttribType == covAttribType) {
878 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
879 } else {
880 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
881 }
882
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000883 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700884 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700885 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
886 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700887 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700888 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700889 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000890 }
891
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000892 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700893 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000894 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700895 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700896 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
897 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700898 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700899 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700900 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000901 }
902
903 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700904 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
905 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
906 target->resetIndexSource();
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],
bsalomon9c0822a2014-08-11 11:07:48 -0700912 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000913 SkASSERT(combinedMatrix.rectStaysRect());
914 SkASSERT(!rects[1].isEmpty());
915
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000916 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000917 combinedMatrix.mapRect(&devOutside, rects[0]);
918 // can't call mapRect for devInside since it calls sort
919 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
920
921 if (devInside.isEmpty()) {
bsalomon9c0822a2014-08-11 11:07:48 -0700922 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000923 return;
924 }
925
bsalomon9c0822a2014-08-11 11:07:48 -0700926 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000927}