blob: e4bf853e36590b5cf2693d925dda12a35ffc792b [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,
52 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000053 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
54 SkASSERT(NULL != vertexBuilder);
55
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000056 // setup the varying for the Axis aligned rect effect
57 // xy -> interpolated offset
58 // zw -> w/2+0.5, h/2+0.5
59 const char *vsRectName, *fsRectName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000060 vertexBuilder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000061 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000062 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
63 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000064
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000065 // TODO: compute all these offsets, spans, and scales in the VS
66 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
67 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
68 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
69 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
70 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
71 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
72 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
73 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
74 // value of coverage that is used. In other words it is the coverage that is
75 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000076 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
77 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000078
79 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000080 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000081 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
82 fsRectName);
83 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000084 builder->fsCodeAppendf(
85 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
86 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000087
88 SkString modulate;
89 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
90 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
91 }
92
93 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
94 return 0;
95 }
96
97 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
98
99 private:
100 typedef GrGLEffect INHERITED;
101 };
102
103
104private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000105 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000106 this->addVertexAttrib(kVec4f_GrSLType);
107 }
108
109 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
110
111 GR_DECLARE_EFFECT_TEST;
112
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000113 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000114};
115
116
117GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
118
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000119GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000120 GrContext* context,
121 const GrDrawTargetCaps&,
122 GrTexture* textures[]) {
123 return GrAlignedRectEffect::Create();
124}
125
126///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000127class GrGLRectEffect;
128
129/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000130 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000131 * for an arbitrarily oriented rect. The rect is specified as:
132 * Center of the rect
133 * Unit vector point down the height of the rect
134 * Half width + 0.5
135 * Half height + 0.5
136 * The center and vector are stored in a vec4 varying ("RectEdge") with the
137 * center in the xy components and the vector in the zw components.
138 * The munged width and height are stored in a vec2 varying ("WidthHeight")
139 * with the width in x and the height in y.
140 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000141class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000142public:
143 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000144 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
145 gRectEffect->ref();
146 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000147 }
148
149 virtual ~GrRectEffect() {}
150
151 static const char* Name() { return "RectEdge"; }
152
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000153 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000154 uint32_t* validFlags) const SK_OVERRIDE {
155 *validFlags = 0;
156 }
157
158 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
159 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
160 }
161
162 class GLEffect : public GrGLEffect {
163 public:
164 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
165 : INHERITED (factory) {}
166
167 virtual void emitCode(GrGLShaderBuilder* builder,
168 const GrDrawEffect& drawEffect,
169 EffectKey key,
170 const char* outputColor,
171 const char* inputColor,
172 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000173 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
174 SkASSERT(NULL != vertexBuilder);
175
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000176 // setup the varying for the center point and the unit vector
177 // that points down the height of the rect
178 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000179 vertexBuilder->addVarying(kVec4f_GrSLType, "RectEdge",
180 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000181 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000182 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
183 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000184
185 // setup the varying for width/2+.5 and height/2+.5
186 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000187 vertexBuilder->addVarying(kVec2f_GrSLType, "WidthHeight",
188 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000189 const SkString* attr1Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000190 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
191 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000192
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000193 // TODO: compute all these offsets, spans, and scales in the VS
194 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
195 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
196 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
197 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
198 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
199 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
200 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
201 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
202 // value of coverage that is used. In other words it is the coverage that is
203 // used in the interior of the rect after the ramp.
204 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
205 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000206
207 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000208 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000209 builder->fragmentPosition(), fsRectEdgeName);
210 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
211 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000212 builder->fsCodeAppendf(
213 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
214 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000215
216 // Compute the coverage for the rect's height and merge with the width
217 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
218 fsRectEdgeName);
219 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000220 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000221 fsWidthHeightName);
222
223 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000224 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000225 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
226 }
227
228 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
229 return 0;
230 }
231
232 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
233
234 private:
235 typedef GrGLEffect INHERITED;
236 };
237
238
239private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000240 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000241 this->addVertexAttrib(kVec4f_GrSLType);
242 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000243 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000244 }
245
246 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
247
248 GR_DECLARE_EFFECT_TEST;
249
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000250 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000251};
252
253
254GR_DEFINE_EFFECT_TEST(GrRectEffect);
255
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000256GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000257 GrContext* context,
258 const GrDrawTargetCaps&,
259 GrTexture* textures[]) {
260 return GrRectEffect::Create();
261}
262
263///////////////////////////////////////////////////////////////////////////////
264
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000265namespace {
266
robertphillips@google.com42903302013-04-20 12:26:07 +0000267extern const GrVertexAttrib gAARectCoverageAttribs[] = {
268 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
269 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
270};
271
272extern const GrVertexAttrib gAARectColorAttribs[] = {
273 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
274 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
275};
276
277static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
278 if (useCoverage) {
279 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
280 } else {
281 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
282 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000283}
284
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000285static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000286 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000287 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
288 r.fRight - dx, r.fBottom - dy, stride);
289}
290
291};
292
293void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000294 SkSafeSetNull(fAAFillRectIndexBuffer);
295 SkSafeSetNull(fAAStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296}
297
robertphillips@google.com6d067302012-12-18 21:47:47 +0000298static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000299 0, 1, 5, 5, 4, 0,
300 1, 2, 6, 6, 5, 1,
301 2, 3, 7, 7, 6, 2,
302 3, 0, 4, 4, 7, 3,
303 4, 5, 6, 6, 7, 4,
304};
305
robertphillips@google.com6d067302012-12-18 21:47:47 +0000306static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
307static const int kVertsPerAAFillRect = 8;
308static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000309
310GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000311 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
312 sizeof(uint16_t) *
313 kNumAAFillRectsInIndexBuffer;
314
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000315 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000316 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000317 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000318 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
319 bool useTempData = (NULL == data);
320 if (useTempData) {
321 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
322 }
323 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
324 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
325 // the inner rect (for AA) and 2 for the inner rect.
326 int baseIdx = i * kIndicesPerAAFillRect;
327 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
328 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
329 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
330 }
331 }
332 if (useTempData) {
333 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
334 GrCrash("Can't get AA Fill Rect indices into buffer!");
335 }
336 SkDELETE_ARRAY(data);
337 } else {
338 fAAFillRectIndexBuffer->unlock();
339 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000340 }
341 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000342
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000343 return fAAFillRectIndexBuffer;
344}
345
robertphillips@google.com6d067302012-12-18 21:47:47 +0000346static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000347 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
348 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
349 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
350 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
351
352 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
353 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
354 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
355 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
356
357 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
358 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
359 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
360 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
361};
362
363int GrAARectRenderer::aaStrokeRectIndexCount() {
364 return GR_ARRAY_COUNT(gStrokeAARectIdx);
365}
366
367GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
368 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000369 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000370 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
371 if (NULL != fAAStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000372#ifdef SK_DEBUG
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000373 bool updated =
374#endif
375 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
376 sizeof(gStrokeAARectIdx));
377 GR_DEBUGASSERT(updated);
378 }
379 }
380 return fAAStrokeRectIndexBuffer;
381}
382
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000383void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
384 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000385 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000386 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000387 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000388 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000389 GrDrawState* drawState = target->drawState();
390
robertphillips@google.com42903302013-04-20 12:26:07 +0000391 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000392
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000393 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000394 if (!geo.succeeded()) {
395 GrPrintf("Failed to get space for vertices!\n");
396 return;
397 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000398
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000399 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
400 if (NULL == indexBuffer) {
401 GrPrintf("Failed to create index buffer!\n");
402 return;
403 }
404
405 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000406 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000407 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000408
409 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
410 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
411
robertphillips@google.com908aed82013-05-28 13:16:20 +0000412 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
413 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
414
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000415 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000416 // Temporarily #if'ed out. We don't want to pass in the devRect but
417 // right now it is computed in GrContext::apply_aa_to_rect and we don't
418 // want to throw away the work
419#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000420 SkRect devRect;
421 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000422#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000423
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000424 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000425 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000426 } else {
427 // compute transformed (1, 0) and (0, 1) vectors
428 SkVector vec[2] = {
429 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
430 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
431 };
432
433 vec[0].normalize();
434 vec[0].scale(SK_ScalarHalf);
435 vec[1].normalize();
436 vec[1].scale(SK_ScalarHalf);
437
robertphillips@google.com91b71162013-05-10 14:09:54 +0000438 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000439 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
440 rect.fRight, rect.fBottom, vsize);
441 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
442
robertphillips@google.com91b71162013-05-10 14:09:54 +0000443 // Now create the inset points and then outset the original
444 // rotated points
445
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000446 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000447 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000448 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
449 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
450 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000451 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000452 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
453 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
454 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000455 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000456 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
457 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
458 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000459 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000460 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
461 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
462 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463
464 verts += sizeof(GrPoint);
465 for (int i = 0; i < 4; ++i) {
466 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
467 }
468
robertphillips@google.com908aed82013-05-28 13:16:20 +0000469 int scale;
470 if (inset < SK_ScalarHalf) {
471 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
472 SkASSERT(scale >= 0 && scale <= 255);
473 } else {
474 scale = 0xff;
475 }
476
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000477 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000478 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000479 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000480 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000481 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000482 innerColor = target->getDrawState().getColor();
483 } else {
484 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
485 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000486 }
487
488 verts += 4 * vsize;
489 for (int i = 0; i < 4; ++i) {
490 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
491 }
492
493 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000494 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
495 kVertsPerAAFillRect,
496 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000497 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000498}
499
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000500namespace {
501
502// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000503struct RectVertex {
504 GrPoint fPos;
505 GrPoint fCenter;
506 GrPoint fDir;
507 GrPoint fWidthHeight;
508};
509
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000510// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000511extern const GrVertexAttrib gAARectVertexAttribs[] = {
512 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
513 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
514 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
515};
516
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000517// Axis Aligned
518struct AARectVertex {
519 GrPoint fPos;
520 GrPoint fOffset;
521 GrPoint fWidthHeight;
522};
523
524// Axis Aligned
525extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
526 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
527 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
528};
529
robertphillips@google.com42903302013-04-20 12:26:07 +0000530};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000531
532void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
533 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000534 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000535 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000536 GrDrawState* drawState = target->drawState();
537
538 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
539 combinedMatrix.mapPoints(&center, 1);
540
541 // compute transformed (0, 1) vector
542 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
543 dir.normalize();
544
545 // compute transformed (width, 0) and (0, height) vectors
546 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000547 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
548 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000549 };
550
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000551 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
552 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000553 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000554 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000555
556 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
557 if (!geo.succeeded()) {
558 GrPrintf("Failed to get space for vertices!\n");
559 return;
560 }
561
562 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
563
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000564 GrEffectRef* effect = GrRectEffect::Create();
565 static const int kRectAttrIndex = 1;
566 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000567 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000568
569 for (int i = 0; i < 4; ++i) {
570 verts[i].fCenter = center;
571 verts[i].fDir = dir;
572 verts[i].fWidthHeight.fX = newWidth;
573 verts[i].fWidthHeight.fY = newHeight;
574 }
575
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000576 SkRect devRect;
577 combinedMatrix.mapRect(&devRect, rect);
578
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000579 SkRect devBounds = {
580 devRect.fLeft - SK_ScalarHalf,
581 devRect.fTop - SK_ScalarHalf,
582 devRect.fRight + SK_ScalarHalf,
583 devRect.fBottom + SK_ScalarHalf
584 };
585
586 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
587 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
588 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
589 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
590
591 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
592 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
593 target->resetIndexSource();
594}
595
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000596void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
597 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000598 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000599 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000600 GrDrawState* drawState = target->drawState();
601 SkASSERT(combinedMatrix.rectStaysRect());
602
603 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000604 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000605
606 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
607 if (!geo.succeeded()) {
608 GrPrintf("Failed to get space for vertices!\n");
609 return;
610 }
611
612 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
613
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000614 GrEffectRef* effect = GrAlignedRectEffect::Create();
615 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000616 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000617
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000618 SkRect devRect;
619 combinedMatrix.mapRect(&devRect, rect);
620
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000621 SkRect devBounds = {
622 devRect.fLeft - SK_ScalarHalf,
623 devRect.fTop - SK_ScalarHalf,
624 devRect.fRight + SK_ScalarHalf,
625 devRect.fBottom + SK_ScalarHalf
626 };
627
628 GrPoint widthHeight = {
629 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
630 SkScalarHalf(devRect.height()) + SK_ScalarHalf
631 };
632
633 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
634 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
635 verts[0].fWidthHeight = widthHeight;
636
637 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
638 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
639 verts[1].fWidthHeight = widthHeight;
640
641 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
642 verts[2].fOffset = widthHeight;
643 verts[2].fWidthHeight = widthHeight;
644
645 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
646 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
647 verts[3].fWidthHeight = widthHeight;
648
649 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
650 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
651 target->resetIndexSource();
652}
653
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000654void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000655 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000656 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000657 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000658 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000659 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000660 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000661 GrVec devStrokeSize;
662 if (width > 0) {
663 devStrokeSize.set(width, width);
664 combinedMatrix.mapVectors(&devStrokeSize, 1);
665 devStrokeSize.setAbs(devStrokeSize);
666 } else {
667 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
668 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000669
robertphillips@google.com18136d12013-05-10 11:05:58 +0000670 const SkScalar dx = devStrokeSize.fX;
671 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000672 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
673 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000674
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000675 // Temporarily #if'ed out. We don't want to pass in the devRect but
676 // right now it is computed in GrContext::apply_aa_to_rect and we don't
677 // want to throw away the work
678#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000679 SkRect devRect;
680 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000681#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000682
bsalomon@google.com81712882012-11-01 17:12:34 +0000683 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000684 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000685 SkScalar w = devRect.width() - dx;
686 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000687 spare = GrMin(w, h);
688 }
689
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000690 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000691 devOutside.outset(rx, ry);
692
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000693 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000694 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000695 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000696 return;
697 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000698
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000699 SkRect devInside(devRect);
700 devInside.inset(rx, ry);
701
702 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
703}
704
705void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
706 GrDrawTarget* target,
707 const SkRect& devOutside,
708 const SkRect& devInside,
709 bool useVertexCoverage) {
710 GrDrawState* drawState = target->drawState();
711
robertphillips@google.com42903302013-04-20 12:26:07 +0000712 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000713
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000714 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000715 if (!geo.succeeded()) {
716 GrPrintf("Failed to get space for vertices!\n");
717 return;
718 }
719 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
720 if (NULL == indexBuffer) {
721 GrPrintf("Failed to create index buffer!\n");
722 return;
723 }
724
725 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000726 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000727 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000728
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000729 // We create vertices for four nested rectangles. There are two ramps from 0 to full
730 // coverage, one on the exterior of the stroke and the other on the interior.
731 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000732 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
733 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
734 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
735 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
736
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000737#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000738 // TODO: this only really works if the X & Y margins are the same all around
739 // the rect
740 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
741 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
742 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
743 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
744 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000745#else
746 SkScalar inset = SK_ScalarHalf;
747#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000748
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000749 // outermost
750 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000751 // inner two
752 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
753 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000754 // innermost
755 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000756
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000757 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000758 verts += sizeof(GrPoint);
759 for (int i = 0; i < 4; ++i) {
760 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
761 }
762
robertphillips@google.com353f0972013-06-28 17:57:06 +0000763 int scale;
764 if (inset < SK_ScalarHalf) {
765 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
766 SkASSERT(scale >= 0 && scale <= 255);
767 } else {
768 scale = 0xff;
769 }
770
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000771 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000772 GrColor innerColor;
773 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000774 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000775 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000776 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000777 innerColor = target->getDrawState().getColor();
778 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000779 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
780 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000781 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000782
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000783 verts += 4 * vsize;
784 for (int i = 0; i < 8; ++i) {
785 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
786 }
787
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000788 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000789 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000790 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000791 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
792 }
793
794 target->setIndexSourceToBuffer(indexBuffer);
795 target->drawIndexed(kTriangles_GrPrimitiveType,
796 0, 0, 16, aaStrokeRectIndexCount());
797}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000798
799void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
800 GrDrawTarget* target,
801 const SkRect rects[2],
802 const SkMatrix& combinedMatrix,
803 bool useVertexCoverage) {
804 SkASSERT(combinedMatrix.rectStaysRect());
805 SkASSERT(!rects[1].isEmpty());
806
807 SkRect devOutside, devInside;
808 combinedMatrix.mapRect(&devOutside, rects[0]);
809 // can't call mapRect for devInside since it calls sort
810 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
811
812 if (devInside.isEmpty()) {
813 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
814 return;
815 }
816
817 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
818}