blob: 76a5c8c8a534a95470324f217585368e9ac1359d [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"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000013
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000014SK_DEFINE_INST_COUNT(GrAARectRenderer)
robertphillips@google.comf6747b02012-06-12 00:32:28 +000015
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000016///////////////////////////////////////////////////////////////////////////////
17class GrGLAlignedRectEffect;
18
19// Axis Aligned special case
20class GrAlignedRectEffect : public GrEffect {
21public:
22 static GrEffectRef* Create() {
23 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
24 gAlignedRectEffect->ref();
25 return gAlignedRectEffect;
26 }
27
28 virtual ~GrAlignedRectEffect() {}
29
30 static const char* Name() { return "AlignedRectEdge"; }
31
32 virtual void getConstantColorComponents(GrColor* color,
33 uint32_t* validFlags) const SK_OVERRIDE {
34 *validFlags = 0;
35 }
36
37 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
38 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
39 }
40
41 class GLEffect : public GrGLEffect {
42 public:
43 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
44 : INHERITED (factory) {}
45
commit-bot@chromium.orga91f0312013-09-06 20:19:56 +000046 virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
47
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000048 virtual void emitCode(GrGLShaderBuilder* builder,
49 const GrDrawEffect& drawEffect,
50 EffectKey key,
51 const char* outputColor,
52 const char* inputColor,
53 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:
106 GrAlignedRectEffect() : GrEffect() {
107 this->addVertexAttrib(kVec4f_GrSLType);
108 }
109
110 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
111
112 GR_DECLARE_EFFECT_TEST;
113
114 typedef GrEffect INHERITED;
115};
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 */
142class GrRectEffect : public GrEffect {
143public:
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
commit-bot@chromium.orga91f0312013-09-06 20:19:56 +0000168 virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
169
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000170 virtual void emitCode(GrGLShaderBuilder* builder,
171 const GrDrawEffect& drawEffect,
172 EffectKey key,
173 const char* outputColor,
174 const char* inputColor,
175 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000176 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
177 SkASSERT(NULL != vertexBuilder);
178
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000179 // setup the varying for the center point and the unit vector
180 // that points down the height of the rect
181 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000182 vertexBuilder->addVarying(kVec4f_GrSLType, "RectEdge",
183 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000184 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000185 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
186 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000187
188 // setup the varying for width/2+.5 and height/2+.5
189 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000190 vertexBuilder->addVarying(kVec2f_GrSLType, "WidthHeight",
191 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000192 const SkString* attr1Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000193 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
194 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000195
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000196 // TODO: compute all these offsets, spans, and scales in the VS
197 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
198 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
199 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
200 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
201 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
202 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
203 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
204 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
205 // value of coverage that is used. In other words it is the coverage that is
206 // used in the interior of the rect after the ramp.
207 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
208 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000209
210 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000211 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000212 builder->fragmentPosition(), fsRectEdgeName);
213 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
214 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000215 builder->fsCodeAppendf(
216 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
217 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000218
219 // Compute the coverage for the rect's height and merge with the width
220 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
221 fsRectEdgeName);
222 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000223 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000224 fsWidthHeightName);
225
226 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000227 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000228 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
229 }
230
231 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
232 return 0;
233 }
234
235 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
236
237 private:
238 typedef GrGLEffect INHERITED;
239 };
240
241
242private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000243 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000244 this->addVertexAttrib(kVec4f_GrSLType);
245 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000246 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000247 }
248
249 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
250
251 GR_DECLARE_EFFECT_TEST;
252
253 typedef GrEffect INHERITED;
254};
255
256
257GR_DEFINE_EFFECT_TEST(GrRectEffect);
258
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000259GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000260 GrContext* context,
261 const GrDrawTargetCaps&,
262 GrTexture* textures[]) {
263 return GrRectEffect::Create();
264}
265
266///////////////////////////////////////////////////////////////////////////////
267
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268namespace {
269
robertphillips@google.com42903302013-04-20 12:26:07 +0000270extern const GrVertexAttrib gAARectCoverageAttribs[] = {
271 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
272 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
273};
274
275extern const GrVertexAttrib gAARectColorAttribs[] = {
276 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
277 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
278};
279
280static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
281 if (useCoverage) {
282 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
283 } else {
284 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
285 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000286}
287
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000288static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000289 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
291 r.fRight - dx, r.fBottom - dy, stride);
292}
293
294};
295
296void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000297 SkSafeSetNull(fAAFillRectIndexBuffer);
298 SkSafeSetNull(fAAStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000299}
300
robertphillips@google.com6d067302012-12-18 21:47:47 +0000301static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000302 0, 1, 5, 5, 4, 0,
303 1, 2, 6, 6, 5, 1,
304 2, 3, 7, 7, 6, 2,
305 3, 0, 4, 4, 7, 3,
306 4, 5, 6, 6, 7, 4,
307};
308
robertphillips@google.com6d067302012-12-18 21:47:47 +0000309static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
310static const int kVertsPerAAFillRect = 8;
311static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000312
313GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000314 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
315 sizeof(uint16_t) *
316 kNumAAFillRectsInIndexBuffer;
317
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000318 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000319 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000320 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000321 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
322 bool useTempData = (NULL == data);
323 if (useTempData) {
324 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
325 }
326 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
327 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
328 // the inner rect (for AA) and 2 for the inner rect.
329 int baseIdx = i * kIndicesPerAAFillRect;
330 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
331 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
332 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
333 }
334 }
335 if (useTempData) {
336 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
337 GrCrash("Can't get AA Fill Rect indices into buffer!");
338 }
339 SkDELETE_ARRAY(data);
340 } else {
341 fAAFillRectIndexBuffer->unlock();
342 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000343 }
344 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000345
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000346 return fAAFillRectIndexBuffer;
347}
348
robertphillips@google.com6d067302012-12-18 21:47:47 +0000349static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000350 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
351 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
352 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
353 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
354
355 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
356 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
357 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
358 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
359
360 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
361 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
362 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
363 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
364};
365
366int GrAARectRenderer::aaStrokeRectIndexCount() {
367 return GR_ARRAY_COUNT(gStrokeAARectIdx);
368}
369
370GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
371 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000372 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000373 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
374 if (NULL != fAAStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000375#ifdef SK_DEBUG
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000376 bool updated =
377#endif
378 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
379 sizeof(gStrokeAARectIdx));
380 GR_DEBUGASSERT(updated);
381 }
382 }
383 return fAAStrokeRectIndexBuffer;
384}
385
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000386void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
387 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000388 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000389 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000390 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000391 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000392 GrDrawState* drawState = target->drawState();
393
robertphillips@google.com42903302013-04-20 12:26:07 +0000394 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000395
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000396 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000397 if (!geo.succeeded()) {
398 GrPrintf("Failed to get space for vertices!\n");
399 return;
400 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000401
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000402 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
403 if (NULL == indexBuffer) {
404 GrPrintf("Failed to create index buffer!\n");
405 return;
406 }
407
408 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000409 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000410 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000411
412 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
413 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
414
robertphillips@google.com908aed82013-05-28 13:16:20 +0000415 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
416 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
417
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000418 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000419 // Temporarily #if'ed out. We don't want to pass in the devRect but
420 // right now it is computed in GrContext::apply_aa_to_rect and we don't
421 // want to throw away the work
422#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000423 SkRect devRect;
424 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000425#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000426
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000427 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000428 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000429 } else {
430 // compute transformed (1, 0) and (0, 1) vectors
431 SkVector vec[2] = {
432 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
433 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
434 };
435
436 vec[0].normalize();
437 vec[0].scale(SK_ScalarHalf);
438 vec[1].normalize();
439 vec[1].scale(SK_ScalarHalf);
440
robertphillips@google.com91b71162013-05-10 14:09:54 +0000441 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000442 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
443 rect.fRight, rect.fBottom, vsize);
444 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
445
robertphillips@google.com91b71162013-05-10 14:09:54 +0000446 // Now create the inset points and then outset the original
447 // rotated points
448
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000449 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000450 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000451 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
452 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
453 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000454 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000455 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
456 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
457 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000458 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000459 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
460 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
461 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000462 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000463 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
464 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
465 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000466
467 verts += sizeof(GrPoint);
468 for (int i = 0; i < 4; ++i) {
469 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
470 }
471
robertphillips@google.com908aed82013-05-28 13:16:20 +0000472 int scale;
473 if (inset < SK_ScalarHalf) {
474 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
475 SkASSERT(scale >= 0 && scale <= 255);
476 } else {
477 scale = 0xff;
478 }
479
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000480 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000481 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000482 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000483 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000484 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000485 innerColor = target->getDrawState().getColor();
486 } else {
487 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
488 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000489 }
490
491 verts += 4 * vsize;
492 for (int i = 0; i < 4; ++i) {
493 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
494 }
495
496 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000497 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
498 kVertsPerAAFillRect,
499 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000500 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000501}
502
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000503namespace {
504
505// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000506struct RectVertex {
507 GrPoint fPos;
508 GrPoint fCenter;
509 GrPoint fDir;
510 GrPoint fWidthHeight;
511};
512
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000513// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000514extern const GrVertexAttrib gAARectVertexAttribs[] = {
515 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
516 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
517 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
518};
519
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000520// Axis Aligned
521struct AARectVertex {
522 GrPoint fPos;
523 GrPoint fOffset;
524 GrPoint fWidthHeight;
525};
526
527// Axis Aligned
528extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
529 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
530 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
531};
532
robertphillips@google.com42903302013-04-20 12:26:07 +0000533};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000534
535void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
536 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000537 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000538 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000539 GrDrawState* drawState = target->drawState();
540
541 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
542 combinedMatrix.mapPoints(&center, 1);
543
544 // compute transformed (0, 1) vector
545 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
546 dir.normalize();
547
548 // compute transformed (width, 0) and (0, height) vectors
549 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000550 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
551 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000552 };
553
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000554 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
555 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000556 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000557 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000558
559 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
560 if (!geo.succeeded()) {
561 GrPrintf("Failed to get space for vertices!\n");
562 return;
563 }
564
565 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
566
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000567 GrEffectRef* effect = GrRectEffect::Create();
568 static const int kRectAttrIndex = 1;
569 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000570 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000571
572 for (int i = 0; i < 4; ++i) {
573 verts[i].fCenter = center;
574 verts[i].fDir = dir;
575 verts[i].fWidthHeight.fX = newWidth;
576 verts[i].fWidthHeight.fY = newHeight;
577 }
578
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000579 SkRect devRect;
580 combinedMatrix.mapRect(&devRect, rect);
581
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000582 SkRect devBounds = {
583 devRect.fLeft - SK_ScalarHalf,
584 devRect.fTop - SK_ScalarHalf,
585 devRect.fRight + SK_ScalarHalf,
586 devRect.fBottom + SK_ScalarHalf
587 };
588
589 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
590 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
591 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
592 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
593
594 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
595 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
596 target->resetIndexSource();
597}
598
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000599void GrAARectRenderer::shaderFillAlignedAARect(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.comb19cb7f2013-05-02 15:37:20 +0000603 GrDrawState* drawState = target->drawState();
604 SkASSERT(combinedMatrix.rectStaysRect());
605
606 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000607 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000608
609 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
610 if (!geo.succeeded()) {
611 GrPrintf("Failed to get space for vertices!\n");
612 return;
613 }
614
615 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
616
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000617 GrEffectRef* effect = GrAlignedRectEffect::Create();
618 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000619 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000620
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000621 SkRect devRect;
622 combinedMatrix.mapRect(&devRect, rect);
623
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000624 SkRect devBounds = {
625 devRect.fLeft - SK_ScalarHalf,
626 devRect.fTop - SK_ScalarHalf,
627 devRect.fRight + SK_ScalarHalf,
628 devRect.fBottom + SK_ScalarHalf
629 };
630
631 GrPoint widthHeight = {
632 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
633 SkScalarHalf(devRect.height()) + SK_ScalarHalf
634 };
635
636 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
637 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
638 verts[0].fWidthHeight = widthHeight;
639
640 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
641 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
642 verts[1].fWidthHeight = widthHeight;
643
644 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
645 verts[2].fOffset = widthHeight;
646 verts[2].fWidthHeight = widthHeight;
647
648 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
649 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
650 verts[3].fWidthHeight = widthHeight;
651
652 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
653 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
654 target->resetIndexSource();
655}
656
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000657void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000658 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000659 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000660 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000661 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000662 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000663 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000664 GrVec devStrokeSize;
665 if (width > 0) {
666 devStrokeSize.set(width, width);
667 combinedMatrix.mapVectors(&devStrokeSize, 1);
668 devStrokeSize.setAbs(devStrokeSize);
669 } else {
670 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
671 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000672
robertphillips@google.com18136d12013-05-10 11:05:58 +0000673 const SkScalar dx = devStrokeSize.fX;
674 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000675 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
676 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000677
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000678 // Temporarily #if'ed out. We don't want to pass in the devRect but
679 // right now it is computed in GrContext::apply_aa_to_rect and we don't
680 // want to throw away the work
681#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000682 SkRect devRect;
683 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000684#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000685
bsalomon@google.com81712882012-11-01 17:12:34 +0000686 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000687 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000688 SkScalar w = devRect.width() - dx;
689 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000690 spare = GrMin(w, h);
691 }
692
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000693 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000694 devOutside.outset(rx, ry);
695
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000696 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000697 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000698 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000699 return;
700 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000701
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000702 SkRect devInside(devRect);
703 devInside.inset(rx, ry);
704
705 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
706}
707
708void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
709 GrDrawTarget* target,
710 const SkRect& devOutside,
711 const SkRect& devInside,
712 bool useVertexCoverage) {
713 GrDrawState* drawState = target->drawState();
714
robertphillips@google.com42903302013-04-20 12:26:07 +0000715 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000716
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000717 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000718 if (!geo.succeeded()) {
719 GrPrintf("Failed to get space for vertices!\n");
720 return;
721 }
722 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
723 if (NULL == indexBuffer) {
724 GrPrintf("Failed to create index buffer!\n");
725 return;
726 }
727
728 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000729 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000730 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000731
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000732 // We create vertices for four nested rectangles. There are two ramps from 0 to full
733 // coverage, one on the exterior of the stroke and the other on the interior.
734 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000735 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
736 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
737 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
738 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
739
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000740#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000741 // TODO: this only really works if the X & Y margins are the same all around
742 // the rect
743 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
744 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
745 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
746 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
747 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000748#else
749 SkScalar inset = SK_ScalarHalf;
750#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000751
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000752 // outermost
753 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000754 // inner two
755 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
756 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000757 // innermost
758 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000759
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000760 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000761 verts += sizeof(GrPoint);
762 for (int i = 0; i < 4; ++i) {
763 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
764 }
765
robertphillips@google.com353f0972013-06-28 17:57:06 +0000766 int scale;
767 if (inset < SK_ScalarHalf) {
768 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
769 SkASSERT(scale >= 0 && scale <= 255);
770 } else {
771 scale = 0xff;
772 }
773
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000774 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000775 GrColor innerColor;
776 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000777 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000778 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000779 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000780 innerColor = target->getDrawState().getColor();
781 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000782 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
783 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000784 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000785
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000786 verts += 4 * vsize;
787 for (int i = 0; i < 8; ++i) {
788 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
789 }
790
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000791 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000792 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000793 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000794 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
795 }
796
797 target->setIndexSourceToBuffer(indexBuffer);
798 target->drawIndexed(kTriangles_GrPrimitiveType,
799 0, 0, 16, aaStrokeRectIndexCount());
800}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000801
802void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
803 GrDrawTarget* target,
804 const SkRect rects[2],
805 const SkMatrix& combinedMatrix,
806 bool useVertexCoverage) {
807 SkASSERT(combinedMatrix.rectStaysRect());
808 SkASSERT(!rects[1].isEmpty());
809
810 SkRect devOutside, devInside;
811 combinedMatrix.mapRect(&devOutside, rects[0]);
812 // can't call mapRect for devInside since it calls sort
813 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
814
815 if (devInside.isEmpty()) {
816 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
817 return;
818 }
819
820 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
821}