blob: 320b3d7cb07069a39ef6d4ca7580bd0d1e8d4a13 [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"
11#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000012#include "SkColorPriv.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000013#include "effects/GrVertexEffect.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000014
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000015SK_DEFINE_INST_COUNT(GrAARectRenderer)
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:
23 static GrEffectRef* Create() {
24 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
42 class GLEffect : public GrGLEffect {
43 public:
44 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
45 : INHERITED (factory) {}
46
47 virtual void emitCode(GrGLShaderBuilder* builder,
48 const GrDrawEffect& drawEffect,
49 EffectKey key,
50 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 {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000054 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
55 SkASSERT(NULL != vertexBuilder);
56
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000057 // setup the varying for the Axis aligned rect effect
58 // xy -> interpolated offset
59 // zw -> w/2+0.5, h/2+0.5
60 const char *vsRectName, *fsRectName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000061 vertexBuilder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000062 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000063 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
64 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000065
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000066 // TODO: compute all these offsets, spans, and scales in the VS
67 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
68 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
69 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
70 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
71 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
72 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
73 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
74 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
75 // value of coverage that is used. In other words it is the coverage that is
76 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000077 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
78 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000079
80 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000081 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000082 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
83 fsRectName);
84 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000085 builder->fsCodeAppendf(
86 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
87 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000088
89 SkString modulate;
90 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
91 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
92 }
93
94 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
95 return 0;
96 }
97
98 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
99
100 private:
101 typedef GrGLEffect INHERITED;
102 };
103
104
105private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000106 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000107 this->addVertexAttrib(kVec4f_GrSLType);
108 }
109
110 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
111
112 GR_DECLARE_EFFECT_TEST;
113
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000114 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000115};
116
117
118GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
119
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000120GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000121 GrContext* context,
122 const GrDrawTargetCaps&,
123 GrTexture* textures[]) {
124 return GrAlignedRectEffect::Create();
125}
126
127///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000128class GrGLRectEffect;
129
130/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000131 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000132 * for an arbitrarily oriented rect. The rect is specified as:
133 * Center of the rect
134 * Unit vector point down the height of the rect
135 * Half width + 0.5
136 * Half height + 0.5
137 * The center and vector are stored in a vec4 varying ("RectEdge") with the
138 * center in the xy components and the vector in the zw components.
139 * The munged width and height are stored in a vec2 varying ("WidthHeight")
140 * with the width in x and the height in y.
141 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000142class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000143public:
144 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000145 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
146 gRectEffect->ref();
147 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000148 }
149
150 virtual ~GrRectEffect() {}
151
152 static const char* Name() { return "RectEdge"; }
153
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000154 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000155 uint32_t* validFlags) const SK_OVERRIDE {
156 *validFlags = 0;
157 }
158
159 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
160 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
161 }
162
163 class GLEffect : public GrGLEffect {
164 public:
165 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
166 : INHERITED (factory) {}
167
168 virtual void emitCode(GrGLShaderBuilder* builder,
169 const GrDrawEffect& drawEffect,
170 EffectKey key,
171 const char* outputColor,
172 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000173 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000174 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000175 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
176 SkASSERT(NULL != vertexBuilder);
177
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000178 // setup the varying for the center point and the unit vector
179 // that points down the height of the rect
180 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000181 vertexBuilder->addVarying(kVec4f_GrSLType, "RectEdge",
182 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000183 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000184 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
185 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000186
187 // setup the varying for width/2+.5 and height/2+.5
188 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000189 vertexBuilder->addVarying(kVec2f_GrSLType, "WidthHeight",
190 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000191 const SkString* attr1Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000192 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
193 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000194
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000195 // TODO: compute all these offsets, spans, and scales in the VS
196 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
197 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
198 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
199 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
200 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
201 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
202 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
203 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
204 // value of coverage that is used. In other words it is the coverage that is
205 // used in the interior of the rect after the ramp.
206 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
207 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000208
209 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000210 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000211 builder->fragmentPosition(), fsRectEdgeName);
212 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
213 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000214 builder->fsCodeAppendf(
215 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
216 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000217
218 // Compute the coverage for the rect's height and merge with the width
219 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
220 fsRectEdgeName);
221 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000222 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000223 fsWidthHeightName);
224
225 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000226 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000227 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
228 }
229
230 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
231 return 0;
232 }
233
234 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
235
236 private:
237 typedef GrGLEffect INHERITED;
238 };
239
240
241private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000242 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000243 this->addVertexAttrib(kVec4f_GrSLType);
244 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000245 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000246 }
247
248 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
249
250 GR_DECLARE_EFFECT_TEST;
251
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000252 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000253};
254
255
256GR_DEFINE_EFFECT_TEST(GrRectEffect);
257
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000258GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000259 GrContext* context,
260 const GrDrawTargetCaps&,
261 GrTexture* textures[]) {
262 return GrRectEffect::Create();
263}
264
265///////////////////////////////////////////////////////////////////////////////
266
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267namespace {
268
robertphillips@google.com42903302013-04-20 12:26:07 +0000269extern const GrVertexAttrib gAARectCoverageAttribs[] = {
270 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
271 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
272};
273
274extern const GrVertexAttrib gAARectColorAttribs[] = {
275 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
276 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
277};
278
279static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
280 if (useCoverage) {
281 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
282 } else {
283 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
284 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000285}
286
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000287static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000288 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000289 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
290 r.fRight - dx, r.fBottom - dy, stride);
291}
292
293};
294
295void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000296 SkSafeSetNull(fAAFillRectIndexBuffer);
297 SkSafeSetNull(fAAStrokeRectIndexBuffer);
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
robertphillips@google.com6d067302012-12-18 21:47:47 +0000308static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
309static const int kVertsPerAAFillRect = 8;
310static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000311
312GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000313 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
314 sizeof(uint16_t) *
315 kNumAAFillRectsInIndexBuffer;
316
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000317 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000318 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000319 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000320 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
321 bool useTempData = (NULL == data);
322 if (useTempData) {
323 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
324 }
325 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
326 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
327 // the inner rect (for AA) and 2 for the inner rect.
328 int baseIdx = i * kIndicesPerAAFillRect;
329 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
330 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
331 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
332 }
333 }
334 if (useTempData) {
335 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
336 GrCrash("Can't get AA Fill Rect indices into buffer!");
337 }
338 SkDELETE_ARRAY(data);
339 } else {
340 fAAFillRectIndexBuffer->unlock();
341 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000342 }
343 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000344
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000345 return fAAFillRectIndexBuffer;
346}
347
robertphillips@google.com6d067302012-12-18 21:47:47 +0000348static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000349 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
350 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
351 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
352 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
353
354 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
355 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
356 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
357 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
358
359 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
360 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
361 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
362 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
363};
364
365int GrAARectRenderer::aaStrokeRectIndexCount() {
366 return GR_ARRAY_COUNT(gStrokeAARectIdx);
367}
368
369GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
370 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000371 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000372 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
373 if (NULL != fAAStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000374#ifdef SK_DEBUG
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000375 bool updated =
376#endif
377 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
378 sizeof(gStrokeAARectIdx));
379 GR_DEBUGASSERT(updated);
380 }
381 }
382 return fAAStrokeRectIndexBuffer;
383}
384
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000385void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
386 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000387 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000388 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000389 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000390 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000391 GrDrawState* drawState = target->drawState();
392
robertphillips@google.com42903302013-04-20 12:26:07 +0000393 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000394
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000395 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000396 if (!geo.succeeded()) {
397 GrPrintf("Failed to get space for vertices!\n");
398 return;
399 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000400
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000401 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
402 if (NULL == indexBuffer) {
403 GrPrintf("Failed to create index buffer!\n");
404 return;
405 }
406
407 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000408 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000409 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000410
411 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
412 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
413
robertphillips@google.com908aed82013-05-28 13:16:20 +0000414 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
415 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
416
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000417 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000418 // Temporarily #if'ed out. We don't want to pass in the devRect but
419 // right now it is computed in GrContext::apply_aa_to_rect and we don't
420 // want to throw away the work
421#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000422 SkRect devRect;
423 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000424#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000425
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000426 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000427 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000428 } else {
429 // compute transformed (1, 0) and (0, 1) vectors
430 SkVector vec[2] = {
431 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
432 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
433 };
434
435 vec[0].normalize();
436 vec[0].scale(SK_ScalarHalf);
437 vec[1].normalize();
438 vec[1].scale(SK_ScalarHalf);
439
robertphillips@google.com91b71162013-05-10 14:09:54 +0000440 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000441 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
442 rect.fRight, rect.fBottom, vsize);
443 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
444
robertphillips@google.com91b71162013-05-10 14:09:54 +0000445 // Now create the inset points and then outset the original
446 // rotated points
447
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000448 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000449 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000450 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
451 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
452 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000453 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000454 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
455 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
456 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000457 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000458 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
459 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
460 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000461 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000462 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
463 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
464 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000465
466 verts += sizeof(GrPoint);
467 for (int i = 0; i < 4; ++i) {
468 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
469 }
470
robertphillips@google.com908aed82013-05-28 13:16:20 +0000471 int scale;
472 if (inset < SK_ScalarHalf) {
473 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
474 SkASSERT(scale >= 0 && scale <= 255);
475 } else {
476 scale = 0xff;
477 }
478
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000479 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000480 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000481 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000482 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000483 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000484 innerColor = target->getDrawState().getColor();
485 } else {
486 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
487 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000488 }
489
490 verts += 4 * vsize;
491 for (int i = 0; i < 4; ++i) {
492 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
493 }
494
495 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000496 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
497 kVertsPerAAFillRect,
498 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000499 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000500}
501
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000502namespace {
503
504// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000505struct RectVertex {
506 GrPoint fPos;
507 GrPoint fCenter;
508 GrPoint fDir;
509 GrPoint fWidthHeight;
510};
511
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000512// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000513extern const GrVertexAttrib gAARectVertexAttribs[] = {
514 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
515 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
516 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
517};
518
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000519// Axis Aligned
520struct AARectVertex {
521 GrPoint fPos;
522 GrPoint fOffset;
523 GrPoint fWidthHeight;
524};
525
526// Axis Aligned
527extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
528 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
529 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
530};
531
robertphillips@google.com42903302013-04-20 12:26:07 +0000532};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000533
534void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
535 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000536 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000537 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000538 GrDrawState* drawState = target->drawState();
539
540 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
541 combinedMatrix.mapPoints(&center, 1);
542
543 // compute transformed (0, 1) vector
544 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
545 dir.normalize();
546
547 // compute transformed (width, 0) and (0, height) vectors
548 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000549 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
550 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000551 };
552
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000553 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
554 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000555 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000556 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000557
558 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
559 if (!geo.succeeded()) {
560 GrPrintf("Failed to get space for vertices!\n");
561 return;
562 }
563
564 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
565
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000566 GrEffectRef* effect = GrRectEffect::Create();
567 static const int kRectAttrIndex = 1;
568 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000569 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000570
571 for (int i = 0; i < 4; ++i) {
572 verts[i].fCenter = center;
573 verts[i].fDir = dir;
574 verts[i].fWidthHeight.fX = newWidth;
575 verts[i].fWidthHeight.fY = newHeight;
576 }
577
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000578 SkRect devRect;
579 combinedMatrix.mapRect(&devRect, rect);
580
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000581 SkRect devBounds = {
582 devRect.fLeft - SK_ScalarHalf,
583 devRect.fTop - SK_ScalarHalf,
584 devRect.fRight + SK_ScalarHalf,
585 devRect.fBottom + SK_ScalarHalf
586 };
587
588 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
589 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
590 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
591 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
592
593 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
594 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
595 target->resetIndexSource();
596}
597
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000598void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
599 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000600 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000601 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000602 GrDrawState* drawState = target->drawState();
603 SkASSERT(combinedMatrix.rectStaysRect());
604
605 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000606 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000607
608 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
609 if (!geo.succeeded()) {
610 GrPrintf("Failed to get space for vertices!\n");
611 return;
612 }
613
614 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
615
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000616 GrEffectRef* effect = GrAlignedRectEffect::Create();
617 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000618 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000619
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000620 SkRect devRect;
621 combinedMatrix.mapRect(&devRect, rect);
622
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000623 SkRect devBounds = {
624 devRect.fLeft - SK_ScalarHalf,
625 devRect.fTop - SK_ScalarHalf,
626 devRect.fRight + SK_ScalarHalf,
627 devRect.fBottom + SK_ScalarHalf
628 };
629
630 GrPoint widthHeight = {
631 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
632 SkScalarHalf(devRect.height()) + SK_ScalarHalf
633 };
634
635 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
636 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
637 verts[0].fWidthHeight = widthHeight;
638
639 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
640 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
641 verts[1].fWidthHeight = widthHeight;
642
643 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
644 verts[2].fOffset = widthHeight;
645 verts[2].fWidthHeight = widthHeight;
646
647 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
648 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
649 verts[3].fWidthHeight = widthHeight;
650
651 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
652 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
653 target->resetIndexSource();
654}
655
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000656void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000657 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000658 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000659 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000660 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000661 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000662 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000663 GrVec devStrokeSize;
664 if (width > 0) {
665 devStrokeSize.set(width, width);
666 combinedMatrix.mapVectors(&devStrokeSize, 1);
667 devStrokeSize.setAbs(devStrokeSize);
668 } else {
669 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
670 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000671
robertphillips@google.com18136d12013-05-10 11:05:58 +0000672 const SkScalar dx = devStrokeSize.fX;
673 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000674 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
675 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000676
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000677 // Temporarily #if'ed out. We don't want to pass in the devRect but
678 // right now it is computed in GrContext::apply_aa_to_rect and we don't
679 // want to throw away the work
680#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000681 SkRect devRect;
682 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000683#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000684
bsalomon@google.com81712882012-11-01 17:12:34 +0000685 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000686 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000687 SkScalar w = devRect.width() - dx;
688 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000689 spare = GrMin(w, h);
690 }
691
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000692 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000693 devOutside.outset(rx, ry);
694
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000695 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000696 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000697 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000698 return;
699 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000700
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000701 SkRect devInside(devRect);
702 devInside.inset(rx, ry);
703
704 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
705}
706
707void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
708 GrDrawTarget* target,
709 const SkRect& devOutside,
710 const SkRect& devInside,
711 bool useVertexCoverage) {
712 GrDrawState* drawState = target->drawState();
713
robertphillips@google.com42903302013-04-20 12:26:07 +0000714 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000715
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000716 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000717 if (!geo.succeeded()) {
718 GrPrintf("Failed to get space for vertices!\n");
719 return;
720 }
721 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
722 if (NULL == indexBuffer) {
723 GrPrintf("Failed to create index buffer!\n");
724 return;
725 }
726
727 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000728 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000729 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000730
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000731 // We create vertices for four nested rectangles. There are two ramps from 0 to full
732 // coverage, one on the exterior of the stroke and the other on the interior.
733 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000734 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
735 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
736 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
737 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
738
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000739#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000740 // TODO: this only really works if the X & Y margins are the same all around
741 // the rect
742 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
743 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
744 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
745 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
746 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000747#else
748 SkScalar inset = SK_ScalarHalf;
749#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000750
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000751 // outermost
752 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000753 // inner two
754 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
755 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000756 // innermost
757 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000758
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000759 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000760 verts += sizeof(GrPoint);
761 for (int i = 0; i < 4; ++i) {
762 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
763 }
764
robertphillips@google.com353f0972013-06-28 17:57:06 +0000765 int scale;
766 if (inset < SK_ScalarHalf) {
767 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
768 SkASSERT(scale >= 0 && scale <= 255);
769 } else {
770 scale = 0xff;
771 }
772
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000773 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000774 GrColor innerColor;
775 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000776 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000777 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000778 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000779 innerColor = target->getDrawState().getColor();
780 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000781 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
782 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000783 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000784
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000785 verts += 4 * vsize;
786 for (int i = 0; i < 8; ++i) {
787 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
788 }
789
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000790 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000791 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000792 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000793 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
794 }
795
796 target->setIndexSourceToBuffer(indexBuffer);
797 target->drawIndexed(kTriangles_GrPrimitiveType,
798 0, 0, 16, aaStrokeRectIndexCount());
799}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000800
801void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
802 GrDrawTarget* target,
803 const SkRect rects[2],
804 const SkMatrix& combinedMatrix,
805 bool useVertexCoverage) {
806 SkASSERT(combinedMatrix.rectStaysRect());
807 SkASSERT(!rects[1].isEmpty());
808
809 SkRect devOutside, devInside;
810 combinedMatrix.mapRect(&devOutside, rects[0]);
811 // can't call mapRect for devInside since it calls sort
812 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
813
814 if (devInside.isEmpty()) {
815 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
816 return;
817 }
818
819 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
820}