blob: d4aad406c61ad56b0a1a6c42de8e5baa39526732 [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
joshualitt74077b92014-10-24 11:26:03 -070048 GrGLVertToFrag v(kVec4f_GrSLType);
49 args.fPB->addVarying("Rect", &v);
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();
joshualitt74077b92014-10-24 11:26:03 -070053 vsBuilder->codeAppendf("\t%s = %s;\n", v.fsIn(), 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
joshualitt74077b92014-10-24 11:26:03 -070057 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", v.fsIn());
58 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", v.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -070059 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(
joshualitt74077b92014-10-24 11:26:03 -070072 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", v.fsIn(),
73 v.fsIn());
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000074 // 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",
joshualitt74077b92014-10-24 11:26:03 -070077 v.fsIn(), v.fsIn());
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
joshualitt74077b92014-10-24 11:26:03 -0700166 GrGLVertToFrag rectEdge(kVec4f_GrSLType);
167 args.fPB->addVarying("RectEdge", &rectEdge);
joshualitt30ba4362014-08-21 20:18:45 -0700168
joshualittc369e7c2014-10-22 10:56:26 -0700169 const GrRectEffect& rectEffect = args.fGP.cast<GrRectEffect>();
170 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt74077b92014-10-24 11:26:03 -0700171 vsBuilder->codeAppendf("%s = %s;", rectEdge.vsOut(), rectEffect.inRectEdge().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000172
173 // setup the varying for width/2+.5 and height/2+.5
joshualitt74077b92014-10-24 11:26:03 -0700174 GrGLVertToFrag widthHeight(kVec2f_GrSLType);
175 args.fPB->addVarying("WidthHeight", &widthHeight);
joshualitt249af152014-09-15 11:41:13 -0700176 vsBuilder->codeAppendf("%s = %s;",
joshualitt74077b92014-10-24 11:26:03 -0700177 widthHeight.vsOut(),
joshualitt249af152014-09-15 11:41:13 -0700178 rectEffect.inWidthHeight().c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000179
joshualittc369e7c2014-10-22 10:56:26 -0700180 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000181 // TODO: compute all these offsets, spans, and scales in the VS
joshualitt74077b92014-10-24 11:26:03 -0700182 fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", widthHeight.fsIn());
183 fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", widthHeight.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700184 fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000185 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
186 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
joshualitt30ba4362014-08-21 20:18:45 -0700187 fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
188 fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000189 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
190 // value of coverage that is used. In other words it is the coverage that is
191 // used in the interior of the rect after the ramp.
joshualitt30ba4362014-08-21 20:18:45 -0700192 fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
193 fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000194
195 // Compute the coverage for the rect's width
joshualitt30ba4362014-08-21 20:18:45 -0700196 fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
joshualitt74077b92014-10-24 11:26:03 -0700197 fsBuilder->fragmentPosition(), rectEdge.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700198 fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
joshualitt74077b92014-10-24 11:26:03 -0700199 rectEdge.fsIn(), rectEdge.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700200 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000201 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
joshualitt74077b92014-10-24 11:26:03 -0700202 widthHeight.fsIn());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203
204 // Compute the coverage for the rect's height and merge with the width
joshualitt30ba4362014-08-21 20:18:45 -0700205 fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
joshualitt74077b92014-10-24 11:26:03 -0700206 rectEdge.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700207 fsBuilder->codeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000208 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
joshualitt74077b92014-10-24 11:26:03 -0700209 widthHeight.fsIn());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000210
commit-bot@chromium.org824c3462013-10-10 06:30:18 +0000211
joshualittc369e7c2014-10-22 10:56:26 -0700212 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
213 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("coverage")).c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000214 }
215
joshualittb0a8a372014-09-23 09:50:21 -0700216 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000217
joshualittb0a8a372014-09-23 09:50:21 -0700218 virtual void setData(const GrGLProgramDataManager& pdman, const GrProcessor&) SK_OVERRIDE {}
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000219
220 private:
joshualitt249af152014-09-15 11:41:13 -0700221 typedef GrGLGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000222 };
223
224
joshualitt249af152014-09-15 11:41:13 -0700225
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000226private:
joshualitt249af152014-09-15 11:41:13 -0700227 GrRectEffect()
228 : fInRectEdge(this->addVertexAttrib(GrShaderVar("inRectEdge",
229 kVec4f_GrSLType,
230 GrShaderVar::kAttribute_TypeModifier)))
231 , fInWidthHeight(this->addVertexAttrib(
232 GrShaderVar("inWidthHeight",
233 kVec2f_GrSLType,
234 GrShaderVar::kAttribute_TypeModifier))) {
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000235 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000236 }
237
bsalomon0e08fc12014-10-15 08:19:04 -0700238 virtual bool onIsEqual(const GrGeometryProcessor&) const SK_OVERRIDE { return true; }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000239
egdaniel1a8ecdf2014-10-03 06:24:12 -0700240 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE {
egdanielccb2e382014-10-13 12:53:46 -0700241 inout->mulByUnknownAlpha();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700242 }
243
joshualitt249af152014-09-15 11:41:13 -0700244 const GrShaderVar& fInRectEdge;
245 const GrShaderVar& fInWidthHeight;
246
joshualittb0a8a372014-09-23 09:50:21 -0700247 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000248
joshualitt249af152014-09-15 11:41:13 -0700249 typedef GrGeometryProcessor INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000250};
251
252
joshualittb0a8a372014-09-23 09:50:21 -0700253GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrRectEffect);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000254
joshualittb0a8a372014-09-23 09:50:21 -0700255GrGeometryProcessor* GrRectEffect::TestCreate(SkRandom* random,
256 GrContext* context,
257 const GrDrawTargetCaps&,
258 GrTexture* textures[]) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000259 return GrRectEffect::Create();
260}
261
262///////////////////////////////////////////////////////////////////////////////
263
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000264namespace {
bsalomon9c0822a2014-08-11 11:07:48 -0700265extern const GrVertexAttrib gAARectAttribs[] = {
266 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
267 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
268 {kVec4ub_GrVertexAttribType, sizeof(SkPoint) + sizeof(SkColor), kCoverage_GrVertexAttribBinding},
robertphillips@google.com42903302013-04-20 12:26:07 +0000269};
270
bsalomonc30aaa02014-08-13 07:15:29 -0700271// Should the coverage be multiplied into the color attrib or use a separate attrib.
272enum CoverageAttribType {
273 kUseColor_CoverageAttribType,
274 kUseCoverage_CoverageAttribType,
275};
276}
277
278static CoverageAttribType set_rect_attribs(GrDrawState* drawState) {
279 if (drawState->canTweakAlphaForCoverage()) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700280 drawState->setVertexAttribs<gAARectAttribs>(2, sizeof(SkPoint) + sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700281 return kUseColor_CoverageAttribType;
282 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700283 drawState->setVertexAttribs<gAARectAttribs>(3, sizeof(SkPoint) + 2 * sizeof(SkColor));
bsalomonc30aaa02014-08-13 07:15:29 -0700284 return kUseCoverage_CoverageAttribType;
285 }
286}
287
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000288static void set_inset_fan(SkPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000289 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
291 r.fRight - dx, r.fBottom - dy, stride);
292}
293
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000294void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000295 SkSafeSetNull(fAAFillRectIndexBuffer);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000296 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
297 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000298}
299
robertphillips@google.com6d067302012-12-18 21:47:47 +0000300static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000301 0, 1, 5, 5, 4, 0,
302 1, 2, 6, 6, 5, 1,
303 2, 3, 7, 7, 6, 2,
304 3, 0, 4, 4, 7, 3,
305 4, 5, 6, 6, 7, 4,
306};
307
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000308static const int kIndicesPerAAFillRect = SK_ARRAY_COUNT(gFillAARectIdx);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000309static const int kVertsPerAAFillRect = 8;
310static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000311
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000312static const uint16_t gMiterStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000313 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
314 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
315 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
316 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
317
318 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
319 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
320 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
321 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
322
323 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
324 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
325 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
326 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
327};
328
joshualitt5ead6da2014-10-22 16:00:29 -0700329static const int kIndicesPerMiterStrokeRect = SK_ARRAY_COUNT(gMiterStrokeAARectIdx);
330static const int kVertsPerMiterStrokeRect = 16;
331static const int kNumMiterStrokeRectsInIndexBuffer = 256;
332
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000333/**
334 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
335 * from the first index. The index layout:
336 * outer AA line: 0~3, 4~7
337 * outer edge: 8~11, 12~15
338 * inner edge: 16~19
339 * inner AA line: 20~23
340 * Following comes a bevel-stroke rect and its indices:
341 *
342 * 4 7
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000343 * *********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000344 * * ______________________________ *
345 * * / 12 15 \ *
346 * * / \ *
347 * 0 * |8 16_____________________19 11 | * 3
348 * * | | | | *
349 * * | | **************** | | *
350 * * | | * 20 23 * | | *
351 * * | | * * | | *
352 * * | | * 21 22 * | | *
353 * * | | **************** | | *
354 * * | |____________________| | *
355 * 1 * |9 17 18 10| * 2
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000356 * * \ / *
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000357 * * \13 __________________________14/ *
358 * * *
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000359 * **********************************
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000360 * 5 6
361 */
362static const uint16_t gBevelStrokeAARectIdx[] = {
363 // Draw outer AA, from outer AA line to outer edge, shift is 0.
364 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
365 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
366 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
367 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
368 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
369 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
370 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
371 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
372
373 // Draw the stroke, from outer edge to inner edge, shift is 8.
374 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
375 1 + 8, 5 + 8, 9 + 8,
376 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
377 6 + 8, 2 + 8, 10 + 8,
378 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
379 3 + 8, 7 + 8, 11 + 8,
380 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
381 4 + 8, 0 + 8, 8 + 8,
382
383 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
384 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
385 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
386 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
387 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
388};
389
joshualitt5ead6da2014-10-22 16:00:29 -0700390static const int kIndicesPerBevelStrokeRect = SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
391static const int kVertsPerBevelStrokeRect = 24;
392static const int kNumBevelStrokeRectsInIndexBuffer = 256;
393
joshualittb44293e2014-10-28 08:12:18 -0700394static int aa_stroke_rect_index_count(bool miterStroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000395 return miterStroke ? SK_ARRAY_COUNT(gMiterStrokeAARectIdx) :
396 SK_ARRAY_COUNT(gBevelStrokeAARectIdx);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000397}
398
joshualittb44293e2014-10-28 08:12:18 -0700399GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(bool miterStroke) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000400 if (miterStroke) {
401 if (NULL == fAAMiterStrokeRectIndexBuffer) {
402 fAAMiterStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700403 fGpu->createInstancedIndexBuffer(gMiterStrokeAARectIdx,
404 kIndicesPerMiterStrokeRect,
405 kNumMiterStrokeRectsInIndexBuffer,
406 kVertsPerMiterStrokeRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000407 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000408 return fAAMiterStrokeRectIndexBuffer;
409 } else {
410 if (NULL == fAABevelStrokeRectIndexBuffer) {
411 fAABevelStrokeRectIndexBuffer =
joshualittb44293e2014-10-28 08:12:18 -0700412 fGpu->createInstancedIndexBuffer(gBevelStrokeAARectIdx,
413 kIndicesPerBevelStrokeRect,
414 kNumBevelStrokeRectsInIndexBuffer,
415 kVertsPerBevelStrokeRect);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000416 }
417 return fAABevelStrokeRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000418 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000419}
420
joshualittb44293e2014-10-28 08:12:18 -0700421void GrAARectRenderer::geometryFillAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000422 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000423 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700424 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000425 GrDrawState* drawState = target->drawState();
426
bsalomon9c0822a2014-08-11 11:07:48 -0700427 GrColor color = drawState->getColor();
428
bsalomonc30aaa02014-08-13 07:15:29 -0700429 CoverageAttribType covAttribType = set_rect_attribs(drawState);
430 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700431 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
432 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000433
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000434 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000435 if (!geo.succeeded()) {
436 GrPrintf("Failed to get space for vertices!\n");
437 return;
438 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000439
joshualitt5ead6da2014-10-22 16:00:29 -0700440 if (NULL == fAAFillRectIndexBuffer) {
joshualittb44293e2014-10-28 08:12:18 -0700441 fAAFillRectIndexBuffer = fGpu->createInstancedIndexBuffer(gFillAARectIdx,
442 kIndicesPerAAFillRect,
443 kNumAAFillRectsInIndexBuffer,
444 kVertsPerAAFillRect);
joshualitt5ead6da2014-10-22 16:00:29 -0700445 }
446 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000447 if (NULL == indexBuffer) {
448 GrPrintf("Failed to create index buffer!\n");
449 return;
450 }
451
452 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700453 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000454
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000455 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700456 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000457
robertphillips@google.com908aed82013-05-28 13:16:20 +0000458 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
459 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
460
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000461 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000462 // Temporarily #if'ed out. We don't want to pass in the devRect but
463 // right now it is computed in GrContext::apply_aa_to_rect and we don't
464 // want to throw away the work
465#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000466 SkRect devRect;
467 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000468#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000469
egdaniel7b3d5ee2014-08-28 05:41:14 -0700470 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
471 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000472 } else {
473 // compute transformed (1, 0) and (0, 1) vectors
474 SkVector vec[2] = {
475 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
476 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
477 };
478
479 vec[0].normalize();
480 vec[0].scale(SK_ScalarHalf);
481 vec[1].normalize();
482 vec[1].scale(SK_ScalarHalf);
483
robertphillips@google.com91b71162013-05-10 14:09:54 +0000484 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000485 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700486 rect.fRight, rect.fBottom, vstride);
487 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000488
robertphillips@google.com91b71162013-05-10 14:09:54 +0000489 // Now create the inset points and then outset the original
490 // rotated points
491
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000492 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700493 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
494 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
495 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000496 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700497 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
498 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
499 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000500 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700501 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
502 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
503 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000504 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700505 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
506 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
507 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000508 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000509
bsalomon9c0822a2014-08-11 11:07:48 -0700510 // 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 +0000511 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000512 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700513 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700514 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
515 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700516 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700517 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700518 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000519 }
520
robertphillips@google.com908aed82013-05-28 13:16:20 +0000521 int scale;
522 if (inset < SK_ScalarHalf) {
523 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
524 SkASSERT(scale >= 0 && scale <= 255);
525 } else {
526 scale = 0xff;
527 }
528
bsalomon9c0822a2014-08-11 11:07:48 -0700529 GrColor innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700530 if (kUseCoverage_CoverageAttribType == covAttribType) {
531 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
532 } else {
533 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
534 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700535 verts += 4 * vstride;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000536 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700537 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700538 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
539 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700540 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700541 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700542 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000543 }
544
545 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000546 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
547 kVertsPerAAFillRect,
548 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000549 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000550}
551
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000552namespace {
553
554// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000555struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000556 SkPoint fPos;
557 SkPoint fCenter;
558 SkPoint fDir;
559 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000560};
561
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000562// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000563extern const GrVertexAttrib gAARectVertexAttribs[] = {
564 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700565 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
566 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000567};
568
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000569// Axis Aligned
570struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000571 SkPoint fPos;
572 SkPoint fOffset;
573 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000574};
575
576// Axis Aligned
577extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
578 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700579 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000580};
581
robertphillips@google.com42903302013-04-20 12:26:07 +0000582};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000583
joshualittb44293e2014-10-28 08:12:18 -0700584void GrAARectRenderer::shaderFillAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000585 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000586 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000587 GrDrawState* drawState = target->drawState();
588
589 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
590 combinedMatrix.mapPoints(&center, 1);
591
592 // compute transformed (0, 1) vector
593 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
594 dir.normalize();
595
596 // compute transformed (width, 0) and (0, height) vectors
597 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000598 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
599 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000600 };
601
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000602 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
603 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700604 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
605 sizeof(RectVertex));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000606
607 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
608 if (!geo.succeeded()) {
609 GrPrintf("Failed to get space for vertices!\n");
610 return;
611 }
612
613 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
614
joshualittb0a8a372014-09-23 09:50:21 -0700615 GrGeometryProcessor* gp = GrRectEffect::Create();
616 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000617
618 for (int i = 0; i < 4; ++i) {
619 verts[i].fCenter = center;
620 verts[i].fDir = dir;
621 verts[i].fWidthHeight.fX = newWidth;
622 verts[i].fWidthHeight.fY = newHeight;
623 }
624
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000625 SkRect devRect;
626 combinedMatrix.mapRect(&devRect, rect);
627
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000628 SkRect devBounds = {
629 devRect.fLeft - SK_ScalarHalf,
630 devRect.fTop - SK_ScalarHalf,
631 devRect.fRight + SK_ScalarHalf,
632 devRect.fBottom + SK_ScalarHalf
633 };
634
635 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
636 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
637 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
638 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
639
joshualittb44293e2014-10-28 08:12:18 -0700640 target->setIndexSourceToBuffer(fGpu->getContext()->getQuadIndexBuffer());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000641 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
642 target->resetIndexSource();
643}
644
joshualittb44293e2014-10-28 08:12:18 -0700645void GrAARectRenderer::shaderFillAlignedAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000646 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000647 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000648 GrDrawState* drawState = target->drawState();
649 SkASSERT(combinedMatrix.rectStaysRect());
650
egdaniel7b3d5ee2014-08-28 05:41:14 -0700651 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
652 sizeof(AARectVertex));
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000653
654 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
655 if (!geo.succeeded()) {
656 GrPrintf("Failed to get space for vertices!\n");
657 return;
658 }
659
660 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
661
joshualittb0a8a372014-09-23 09:50:21 -0700662 GrGeometryProcessor* gp = GrAlignedRectEffect::Create();
663 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000664
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000665 SkRect devRect;
666 combinedMatrix.mapRect(&devRect, rect);
667
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000668 SkRect devBounds = {
669 devRect.fLeft - SK_ScalarHalf,
670 devRect.fTop - SK_ScalarHalf,
671 devRect.fRight + SK_ScalarHalf,
672 devRect.fBottom + SK_ScalarHalf
673 };
674
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000675 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000676 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
677 SkScalarHalf(devRect.height()) + SK_ScalarHalf
678 };
679
680 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
681 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
682 verts[0].fWidthHeight = widthHeight;
683
684 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
685 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
686 verts[1].fWidthHeight = widthHeight;
687
688 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
689 verts[2].fOffset = widthHeight;
690 verts[2].fWidthHeight = widthHeight;
691
692 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
693 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
694 verts[3].fWidthHeight = widthHeight;
695
joshualittb44293e2014-10-28 08:12:18 -0700696 target->setIndexSourceToBuffer(fGpu->getContext()->getQuadIndexBuffer());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000697 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
698 target->resetIndexSource();
699}
700
joshualittb44293e2014-10-28 08:12:18 -0700701void GrAARectRenderer::strokeAARect(GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000702 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000703 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000704 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700705 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000706 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700707 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000708 if (width > 0) {
709 devStrokeSize.set(width, width);
710 combinedMatrix.mapVectors(&devStrokeSize, 1);
711 devStrokeSize.setAbs(devStrokeSize);
712 } else {
713 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
714 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000715
robertphillips@google.com18136d12013-05-10 11:05:58 +0000716 const SkScalar dx = devStrokeSize.fX;
717 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000718 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
719 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000720
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000721 // Temporarily #if'ed out. We don't want to pass in the devRect but
722 // right now it is computed in GrContext::apply_aa_to_rect and we don't
723 // want to throw away the work
724#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000725 SkRect devRect;
726 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000727#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000728
bsalomon@google.com81712882012-11-01 17:12:34 +0000729 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000730 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000731 SkScalar w = devRect.width() - dx;
732 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000733 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000734 }
735
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000736 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000737 devOutside.outset(rx, ry);
738
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000739 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700740 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000741 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700742 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
743 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000744 miterStroke = false;
745 }
746
747 if (spare <= 0 && miterStroke) {
joshualittb44293e2014-10-28 08:12:18 -0700748 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000749 return;
750 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000751
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000752 SkRect devInside(devRect);
753 devInside.inset(rx, ry);
754
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000755 SkRect devOutsideAssist(devRect);
756
757 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
758 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000759 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000760 if (!miterStroke) {
761 devOutside.inset(0, ry);
762 devOutsideAssist.outset(0, ry);
763 }
764
joshualittb44293e2014-10-28 08:12:18 -0700765 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000766}
767
joshualittb44293e2014-10-28 08:12:18 -0700768void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000769 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000770 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000771 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000772 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000773 GrDrawState* drawState = target->drawState();
774
bsalomonc30aaa02014-08-13 07:15:29 -0700775 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700776
777 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700778 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700779 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
780 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000781
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000782 int innerVertexNum = 4;
783 int outerVertexNum = miterStroke ? 4 : 8;
784 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
785
786 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000787 if (!geo.succeeded()) {
788 GrPrintf("Failed to get space for vertices!\n");
789 return;
790 }
joshualittb44293e2014-10-28 08:12:18 -0700791 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000792 if (NULL == indexBuffer) {
793 GrPrintf("Failed to create index buffer!\n");
794 return;
795 }
796
797 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700798 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000799
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000800 // We create vertices for four nested rectangles. There are two ramps from 0 to full
801 // coverage, one on the exterior of the stroke and the other on the interior.
802 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000803 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700804 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
805 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
806 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000807
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000808#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000809 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700810 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000811 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
812 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
813 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000814 if (miterStroke) {
815 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
816 } else {
817 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
818 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000819 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000820#else
821 SkScalar inset = SK_ScalarHalf;
822#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000823
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000824 if (miterStroke) {
825 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700826 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000827 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700828 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
829 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000830 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700831 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000832 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700833 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
834 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000835 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700836 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
837 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000838 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700839 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
840 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000841 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700842 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000843 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700844 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000845 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000846
bsalomon9c0822a2014-08-11 11:07:48 -0700847 // 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 +0000848 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000849 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000850 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700851 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700852 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
853 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700854 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700855 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700856 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000857 }
858
bsalomon9c0822a2014-08-11 11:07:48 -0700859 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000860 int scale;
861 if (inset < SK_ScalarHalf) {
862 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
863 SkASSERT(scale >= 0 && scale <= 255);
864 } else {
865 scale = 0xff;
866 }
867
egdaniel7b3d5ee2014-08-28 05:41:14 -0700868 verts += outerVertexNum * vstride;
bsalomonc30aaa02014-08-13 07:15:29 -0700869 GrColor innerCoverage;
870 if (kUseCoverage_CoverageAttribType == covAttribType) {
871 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
872 } else {
873 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
874 }
875
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000876 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700877 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700878 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
879 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700880 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700881 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700882 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000883 }
884
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000885 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700886 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000887 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700888 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700889 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
890 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700891 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700892 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700893 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000894 }
895
896 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700897 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
joshualittb44293e2014-10-28 08:12:18 -0700898 totalVertexNum, aa_stroke_rect_index_count(miterStroke));
joshualitt5ead6da2014-10-22 16:00:29 -0700899 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000900}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000901
joshualittb44293e2014-10-28 08:12:18 -0700902void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000903 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700904 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000905 SkASSERT(combinedMatrix.rectStaysRect());
906 SkASSERT(!rects[1].isEmpty());
907
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000908 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000909 combinedMatrix.mapRect(&devOutside, rects[0]);
910 // can't call mapRect for devInside since it calls sort
911 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
912
913 if (devInside.isEmpty()) {
joshualittb44293e2014-10-28 08:12:18 -0700914 this->fillAARect(target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000915 return;
916 }
917
joshualittb44293e2014-10-28 08:12:18 -0700918 this->geometryStrokeAARect(target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000919}