blob: 18bba5a1b8335a387476fee31902a5ed90deb235 [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
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000394int GrAARectRenderer::aaStrokeRectIndexCount(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
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000399GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
400 if (miterStroke) {
401 if (NULL == fAAMiterStrokeRectIndexBuffer) {
402 fAAMiterStrokeRectIndexBuffer =
joshualitt5ead6da2014-10-22 16:00:29 -0700403 gpu->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 =
joshualitt5ead6da2014-10-22 16:00:29 -0700412 gpu->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
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000421void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
422 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000423 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000424 const SkMatrix& combinedMatrix,
bsalomon9c0822a2014-08-11 11:07:48 -0700425 const SkRect& devRect) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000426 GrDrawState* drawState = target->drawState();
427
bsalomon9c0822a2014-08-11 11:07:48 -0700428 GrColor color = drawState->getColor();
429
bsalomonc30aaa02014-08-13 07:15:29 -0700430 CoverageAttribType covAttribType = set_rect_attribs(drawState);
431 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700432 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
433 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000435 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000436 if (!geo.succeeded()) {
437 GrPrintf("Failed to get space for vertices!\n");
438 return;
439 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000440
joshualitt5ead6da2014-10-22 16:00:29 -0700441 if (NULL == fAAFillRectIndexBuffer) {
442 fAAFillRectIndexBuffer = gpu->createInstancedIndexBuffer(gFillAARectIdx,
443 kIndicesPerAAFillRect,
444 kNumAAFillRectsInIndexBuffer,
445 kVertsPerAAFillRect);
446 }
447 GrIndexBuffer* indexBuffer = fAAFillRectIndexBuffer;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000448 if (NULL == indexBuffer) {
449 GrPrintf("Failed to create index buffer!\n");
450 return;
451 }
452
453 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700454 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000455
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000456 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700457 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000458
robertphillips@google.com908aed82013-05-28 13:16:20 +0000459 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
460 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
461
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000462 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000463 // Temporarily #if'ed out. We don't want to pass in the devRect but
464 // right now it is computed in GrContext::apply_aa_to_rect and we don't
465 // want to throw away the work
466#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000467 SkRect devRect;
468 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000469#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000470
egdaniel7b3d5ee2014-08-28 05:41:14 -0700471 set_inset_fan(fan0Pos, vstride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
472 set_inset_fan(fan1Pos, vstride, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000473 } else {
474 // compute transformed (1, 0) and (0, 1) vectors
475 SkVector vec[2] = {
476 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
477 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
478 };
479
480 vec[0].normalize();
481 vec[0].scale(SK_ScalarHalf);
482 vec[1].normalize();
483 vec[1].scale(SK_ScalarHalf);
484
robertphillips@google.com91b71162013-05-10 14:09:54 +0000485 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000486 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
egdaniel7b3d5ee2014-08-28 05:41:14 -0700487 rect.fRight, rect.fBottom, vstride);
488 combinedMatrix.mapPointsWithStride(fan0Pos, vstride, 4);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000489
robertphillips@google.com91b71162013-05-10 14:09:54 +0000490 // Now create the inset points and then outset the original
491 // rotated points
492
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000493 // TL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700494 *((SkPoint*)((intptr_t)fan1Pos + 0 * vstride)) =
495 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) + vec[0] + vec[1];
496 *((SkPoint*)((intptr_t)fan0Pos + 0 * vstride)) -= vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000497 // BL
egdaniel7b3d5ee2014-08-28 05:41:14 -0700498 *((SkPoint*)((intptr_t)fan1Pos + 1 * vstride)) =
499 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) + vec[0] - vec[1];
500 *((SkPoint*)((intptr_t)fan0Pos + 1 * vstride)) -= vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000501 // BR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700502 *((SkPoint*)((intptr_t)fan1Pos + 2 * vstride)) =
503 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) - vec[0] - vec[1];
504 *((SkPoint*)((intptr_t)fan0Pos + 2 * vstride)) += vec[0] + vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000505 // TR
egdaniel7b3d5ee2014-08-28 05:41:14 -0700506 *((SkPoint*)((intptr_t)fan1Pos + 3 * vstride)) =
507 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) - vec[0] + vec[1];
508 *((SkPoint*)((intptr_t)fan0Pos + 3 * vstride)) += vec[0] - vec[1];
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000509 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000510
bsalomon9c0822a2014-08-11 11:07:48 -0700511 // 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 +0000512 verts += sizeof(SkPoint);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000513 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700514 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700515 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
516 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700517 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700518 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700519 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000520 }
521
robertphillips@google.com908aed82013-05-28 13:16:20 +0000522 int scale;
523 if (inset < SK_ScalarHalf) {
524 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
525 SkASSERT(scale >= 0 && scale <= 255);
526 } else {
527 scale = 0xff;
528 }
529
bsalomon9c0822a2014-08-11 11:07:48 -0700530 GrColor innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700531 if (kUseCoverage_CoverageAttribType == covAttribType) {
532 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
533 } else {
534 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
535 }
egdaniel7b3d5ee2014-08-28 05:41:14 -0700536 verts += 4 * vstride;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000537 for (int i = 0; i < 4; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700538 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700539 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
540 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700541 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700542 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700543 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000544 }
545
546 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000547 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
548 kVertsPerAAFillRect,
549 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000550 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000551}
552
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000553namespace {
554
555// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000556struct RectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000557 SkPoint fPos;
558 SkPoint fCenter;
559 SkPoint fDir;
560 SkPoint fWidthHeight;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000561};
562
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000563// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000564extern const GrVertexAttrib gAARectVertexAttribs[] = {
565 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700566 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
567 { kVec2f_GrVertexAttribType, 3*sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding }
robertphillips@google.com42903302013-04-20 12:26:07 +0000568};
569
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000570// Axis Aligned
571struct AARectVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000572 SkPoint fPos;
573 SkPoint fOffset;
574 SkPoint fWidthHeight;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000575};
576
577// Axis Aligned
578extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
579 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
joshualittb0a8a372014-09-23 09:50:21 -0700580 { kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding },
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000581};
582
robertphillips@google.com42903302013-04-20 12:26:07 +0000583};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000584
585void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
586 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000587 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000588 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000589 GrDrawState* drawState = target->drawState();
590
591 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
592 combinedMatrix.mapPoints(&center, 1);
593
594 // compute transformed (0, 1) vector
595 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
596 dir.normalize();
597
598 // compute transformed (width, 0) and (0, height) vectors
599 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000600 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
601 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000602 };
603
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000604 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
605 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
egdaniel7b3d5ee2014-08-28 05:41:14 -0700606 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs),
607 sizeof(RectVertex));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000608
609 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
610 if (!geo.succeeded()) {
611 GrPrintf("Failed to get space for vertices!\n");
612 return;
613 }
614
615 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
616
joshualittb0a8a372014-09-23 09:50:21 -0700617 GrGeometryProcessor* gp = GrRectEffect::Create();
618 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000619
620 for (int i = 0; i < 4; ++i) {
621 verts[i].fCenter = center;
622 verts[i].fDir = dir;
623 verts[i].fWidthHeight.fX = newWidth;
624 verts[i].fWidthHeight.fY = newHeight;
625 }
626
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000627 SkRect devRect;
628 combinedMatrix.mapRect(&devRect, rect);
629
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000630 SkRect devBounds = {
631 devRect.fLeft - SK_ScalarHalf,
632 devRect.fTop - SK_ScalarHalf,
633 devRect.fRight + SK_ScalarHalf,
634 devRect.fBottom + SK_ScalarHalf
635 };
636
637 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
638 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
639 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
640 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
641
642 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
643 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
644 target->resetIndexSource();
645}
646
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000647void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
648 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000649 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000650 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000651 GrDrawState* drawState = target->drawState();
652 SkASSERT(combinedMatrix.rectStaysRect());
653
egdaniel7b3d5ee2014-08-28 05:41:14 -0700654 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs),
655 sizeof(AARectVertex));
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000656
657 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
658 if (!geo.succeeded()) {
659 GrPrintf("Failed to get space for vertices!\n");
660 return;
661 }
662
663 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
664
joshualittb0a8a372014-09-23 09:50:21 -0700665 GrGeometryProcessor* gp = GrAlignedRectEffect::Create();
666 drawState->setGeometryProcessor(gp)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000667
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000668 SkRect devRect;
669 combinedMatrix.mapRect(&devRect, rect);
670
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000671 SkRect devBounds = {
672 devRect.fLeft - SK_ScalarHalf,
673 devRect.fTop - SK_ScalarHalf,
674 devRect.fRight + SK_ScalarHalf,
675 devRect.fBottom + SK_ScalarHalf
676 };
677
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000678 SkPoint widthHeight = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000679 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
680 SkScalarHalf(devRect.height()) + SK_ScalarHalf
681 };
682
683 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
684 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
685 verts[0].fWidthHeight = widthHeight;
686
687 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
688 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
689 verts[1].fWidthHeight = widthHeight;
690
691 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
692 verts[2].fOffset = widthHeight;
693 verts[2].fWidthHeight = widthHeight;
694
695 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
696 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
697 verts[3].fWidthHeight = widthHeight;
698
699 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
700 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
701 target->resetIndexSource();
702}
703
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000704void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000705 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000706 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000707 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000708 const SkRect& devRect,
bsalomon9c0822a2014-08-11 11:07:48 -0700709 const SkStrokeRec& stroke) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000710 SkVector devStrokeSize;
egdanield58a0ba2014-06-11 10:30:05 -0700711 SkScalar width = stroke.getWidth();
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000712 if (width > 0) {
713 devStrokeSize.set(width, width);
714 combinedMatrix.mapVectors(&devStrokeSize, 1);
715 devStrokeSize.setAbs(devStrokeSize);
716 } else {
717 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
718 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000719
robertphillips@google.com18136d12013-05-10 11:05:58 +0000720 const SkScalar dx = devStrokeSize.fX;
721 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000722 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
723 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000724
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000725 // Temporarily #if'ed out. We don't want to pass in the devRect but
726 // right now it is computed in GrContext::apply_aa_to_rect and we don't
727 // want to throw away the work
728#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000729 SkRect devRect;
730 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000731#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000732
bsalomon@google.com81712882012-11-01 17:12:34 +0000733 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000734 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000735 SkScalar w = devRect.width() - dx;
736 SkScalar h = devRect.height() - dy;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000737 spare = SkTMin(w, h);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000738 }
739
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000740 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000741 devOutside.outset(rx, ry);
742
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000743 bool miterStroke = true;
yunchao.he2bff2302014-07-28 19:18:49 -0700744 // For hairlines, make bevel and round joins appear the same as mitered ones.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000745 // small miter limit means right angles show bevel...
yunchao.he2bff2302014-07-28 19:18:49 -0700746 if ((width > 0) && (stroke.getJoin() != SkPaint::kMiter_Join ||
747 stroke.getMiter() < SK_ScalarSqrt2)) {
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000748 miterStroke = false;
749 }
750
751 if (spare <= 0 && miterStroke) {
bsalomon9c0822a2014-08-11 11:07:48 -0700752 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000753 return;
754 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000755
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000756 SkRect devInside(devRect);
757 devInside.inset(rx, ry);
758
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000759 SkRect devOutsideAssist(devRect);
760
761 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
762 // to draw the outer of the rect. Because there are 8 vertices on the outer
skia.committer@gmail.com26144182013-11-07 07:02:19 +0000763 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000764 if (!miterStroke) {
765 devOutside.inset(0, ry);
766 devOutsideAssist.outset(0, ry);
767 }
768
bsalomon9c0822a2014-08-11 11:07:48 -0700769 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, miterStroke);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000770}
771
772void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
773 GrDrawTarget* target,
774 const SkRect& devOutside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000775 const SkRect& devOutsideAssist,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000776 const SkRect& devInside,
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000777 bool miterStroke) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000778 GrDrawState* drawState = target->drawState();
779
bsalomonc30aaa02014-08-13 07:15:29 -0700780 CoverageAttribType covAttribType = set_rect_attribs(drawState);
bsalomon9c0822a2014-08-11 11:07:48 -0700781
782 GrColor color = drawState->getColor();
bsalomonc30aaa02014-08-13 07:15:29 -0700783 if (kUseCoverage_CoverageAttribType == covAttribType && GrColorIsOpaque(color)) {
bsalomon9c0822a2014-08-11 11:07:48 -0700784 drawState->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
785 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000786
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000787 int innerVertexNum = 4;
788 int outerVertexNum = miterStroke ? 4 : 8;
789 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
790
791 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000792 if (!geo.succeeded()) {
793 GrPrintf("Failed to get space for vertices!\n");
794 return;
795 }
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000796 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000797 if (NULL == indexBuffer) {
798 GrPrintf("Failed to create index buffer!\n");
799 return;
800 }
801
802 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
egdaniel7b3d5ee2014-08-28 05:41:14 -0700803 size_t vstride = drawState->getVertexStride();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000804
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000805 // We create vertices for four nested rectangles. There are two ramps from 0 to full
806 // coverage, one on the exterior of the stroke and the other on the interior.
807 // The following pointers refer to the four rects, from outermost to innermost.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000808 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
egdaniel7b3d5ee2014-08-28 05:41:14 -0700809 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstride);
810 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * vstride);
811 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vstride);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000812
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000813#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000814 // TODO: this only really works if the X & Y margins are the same all around
robertphillips183e9852014-10-21 11:25:37 -0700815 // the rect (or if they are all >= 1.0).
robertphillips@google.com353f0972013-06-28 17:57:06 +0000816 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
817 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
818 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000819 if (miterStroke) {
820 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
821 } else {
822 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
823 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000824 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000825#else
826 SkScalar inset = SK_ScalarHalf;
827#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000828
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000829 if (miterStroke) {
830 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700831 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000832 // inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700833 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
834 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000835 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700836 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000837 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700838 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride);
839 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertexNum + 4) * vstride);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000840 // outermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700841 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
842 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000843 // outer one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700844 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset);
845 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000846 // inner one of the inner two
egdaniel7b3d5ee2014-08-28 05:41:14 -0700847 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000848 // innermost
egdaniel7b3d5ee2014-08-28 05:41:14 -0700849 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHalf);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000850 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000851
bsalomon9c0822a2014-08-11 11:07:48 -0700852 // 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 +0000853 // The outermost rect has 0 coverage
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000854 verts += sizeof(SkPoint);
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000855 for (int i = 0; i < outerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700856 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700857 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
858 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700859 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700860 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700861 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000862 }
863
bsalomon9c0822a2014-08-11 11:07:48 -0700864 // scale is the coverage for the the inner two rects.
robertphillips@google.com353f0972013-06-28 17:57:06 +0000865 int scale;
866 if (inset < SK_ScalarHalf) {
867 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
868 SkASSERT(scale >= 0 && scale <= 255);
869 } else {
870 scale = 0xff;
871 }
872
egdaniel7b3d5ee2014-08-28 05:41:14 -0700873 verts += outerVertexNum * vstride;
bsalomonc30aaa02014-08-13 07:15:29 -0700874 GrColor innerCoverage;
875 if (kUseCoverage_CoverageAttribType == covAttribType) {
876 innerCoverage = GrColorPackRGBA(scale, scale, scale, scale);
877 } else {
878 innerCoverage = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
879 }
880
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000881 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700882 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700883 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
884 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700885 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700886 *reinterpret_cast<GrColor*>(verts + i * vstride) = innerCoverage;
bsalomonc30aaa02014-08-13 07:15:29 -0700887 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000888 }
889
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000890 // The innermost rect has 0 coverage
egdaniel7b3d5ee2014-08-28 05:41:14 -0700891 verts += (outerVertexNum + innerVertexNum) * vstride;
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000892 for (int i = 0; i < innerVertexNum; ++i) {
bsalomonc30aaa02014-08-13 07:15:29 -0700893 if (kUseCoverage_CoverageAttribType == covAttribType) {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700894 *reinterpret_cast<GrColor*>(verts + i * vstride) = color;
895 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700896 } else {
egdaniel7b3d5ee2014-08-28 05:41:14 -0700897 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0;
bsalomonc30aaa02014-08-13 07:15:29 -0700898 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000899 }
900
901 target->setIndexSourceToBuffer(indexBuffer);
joshualitt5ead6da2014-10-22 16:00:29 -0700902 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
903 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
904 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000905}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000906
907void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
908 GrDrawTarget* target,
909 const SkRect rects[2],
bsalomon9c0822a2014-08-11 11:07:48 -0700910 const SkMatrix& combinedMatrix) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000911 SkASSERT(combinedMatrix.rectStaysRect());
912 SkASSERT(!rects[1].isEmpty());
913
commit-bot@chromium.org6006d0f2013-11-06 10:08:21 +0000914 SkRect devOutside, devOutsideAssist, devInside;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000915 combinedMatrix.mapRect(&devOutside, rects[0]);
916 // can't call mapRect for devInside since it calls sort
917 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
918
919 if (devInside.isEmpty()) {
bsalomon9c0822a2014-08-11 11:07:48 -0700920 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000921 return;
922 }
923
bsalomon9c0822a2014-08-11 11:07:48 -0700924 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist, devInside, true);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000925}