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