blob: b2052a8d286e67bf2bff6432b2361b1231b991dd [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"
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000011#include "gl/GrGLVertexEffect.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000012#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000013#include "SkColorPriv.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000014#include "effects/GrVertexEffect.h"
robertphillips@google.comf6747b02012-06-12 00:32:28 +000015
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000016SK_DEFINE_INST_COUNT(GrAARectRenderer)
robertphillips@google.comf6747b02012-06-12 00:32:28 +000017
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000018///////////////////////////////////////////////////////////////////////////////
19class GrGLAlignedRectEffect;
20
21// Axis Aligned special case
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000022class GrAlignedRectEffect : public GrVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000023public:
24 static GrEffectRef* Create() {
25 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
26 gAlignedRectEffect->ref();
27 return gAlignedRectEffect;
28 }
29
30 virtual ~GrAlignedRectEffect() {}
31
32 static const char* Name() { return "AlignedRectEdge"; }
33
34 virtual void getConstantColorComponents(GrColor* color,
35 uint32_t* validFlags) const SK_OVERRIDE {
36 *validFlags = 0;
37 }
38
39 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
40 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
41 }
42
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000043 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000044 public:
45 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
46 : INHERITED (factory) {}
47
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000048 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000049 const GrDrawEffect& drawEffect,
50 EffectKey key,
51 const char* outputColor,
52 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +000053 const TransformedCoordsArray&,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000054 const TextureSamplerArray& samplers) SK_OVERRIDE {
55 // setup the varying for the Axis aligned rect effect
56 // xy -> interpolated offset
57 // zw -> w/2+0.5, h/2+0.5
58 const char *vsRectName, *fsRectName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000059 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000060 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000061 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
62 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000063
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000064 // TODO: compute all these offsets, spans, and scales in the VS
65 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
66 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
67 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
68 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
69 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
70 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
71 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
72 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
73 // value of coverage that is used. In other words it is the coverage that is
74 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000075 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
76 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000077
78 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000079 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000080 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
81 fsRectName);
82 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000083 builder->fsCodeAppendf(
84 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
85 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000086
87 SkString modulate;
88 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
89 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
90 }
91
92 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
93 return 0;
94 }
95
96 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
97
98 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +000099 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000100 };
101
102
103private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000104 GrAlignedRectEffect() : GrVertexEffect() {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000105 this->addVertexAttrib(kVec4f_GrSLType);
106 }
107
108 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
109
110 GR_DECLARE_EFFECT_TEST;
111
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000112 typedef GrVertexEffect INHERITED;
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000113};
114
115
116GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
117
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000118GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000119 GrContext* context,
120 const GrDrawTargetCaps&,
121 GrTexture* textures[]) {
122 return GrAlignedRectEffect::Create();
123}
124
125///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000126class GrGLRectEffect;
127
128/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000129 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000130 * for an arbitrarily oriented rect. The rect is specified as:
131 * Center of the rect
132 * Unit vector point down the height of the rect
133 * Half width + 0.5
134 * Half height + 0.5
135 * The center and vector are stored in a vec4 varying ("RectEdge") with the
136 * center in the xy components and the vector in the zw components.
137 * The munged width and height are stored in a vec2 varying ("WidthHeight")
138 * with the width in x and the height in y.
139 */
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000140class GrRectEffect : public GrVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000141public:
142 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000143 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
144 gRectEffect->ref();
145 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000146 }
147
148 virtual ~GrRectEffect() {}
149
150 static const char* Name() { return "RectEdge"; }
151
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000152 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000153 uint32_t* validFlags) const SK_OVERRIDE {
154 *validFlags = 0;
155 }
156
157 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
158 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
159 }
160
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000161 class GLEffect : public GrGLVertexEffect {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000162 public:
163 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
164 : INHERITED (factory) {}
165
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000166 virtual void emitCode(GrGLFullShaderBuilder* builder,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000167 const GrDrawEffect& drawEffect,
168 EffectKey key,
169 const char* outputColor,
170 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000171 const TransformedCoordsArray&,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000172 const TextureSamplerArray& samplers) SK_OVERRIDE {
173 // setup the varying for the center point and the unit vector
174 // that points down the height of the rect
175 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000176 builder->addVarying(kVec4f_GrSLType, "RectEdge",
177 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000178 const SkString* attr0Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000179 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
180 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000181
182 // setup the varying for width/2+.5 and height/2+.5
183 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000184 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
185 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000186 const SkString* attr1Name =
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000187 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
188 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000189
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000190 // TODO: compute all these offsets, spans, and scales in the VS
191 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
192 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
193 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
194 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
195 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
196 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
197 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
198 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
199 // value of coverage that is used. In other words it is the coverage that is
200 // used in the interior of the rect after the ramp.
201 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
202 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000203
204 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000205 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000206 builder->fragmentPosition(), fsRectEdgeName);
207 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
208 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000209 builder->fsCodeAppendf(
210 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
211 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000212
213 // Compute the coverage for the rect's height and merge with the width
214 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
215 fsRectEdgeName);
216 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000217 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000218 fsWidthHeightName);
219
220 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000221 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000222 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
223 }
224
225 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
226 return 0;
227 }
228
229 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
230
231 private:
commit-bot@chromium.org261dc562013-10-04 15:42:56 +0000232 typedef GrGLVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000233 };
234
235
236private:
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000237 GrRectEffect() : GrVertexEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000238 this->addVertexAttrib(kVec4f_GrSLType);
239 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000240 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000241 }
242
243 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
244
245 GR_DECLARE_EFFECT_TEST;
246
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +0000247 typedef GrVertexEffect INHERITED;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000248};
249
250
251GR_DEFINE_EFFECT_TEST(GrRectEffect);
252
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000253GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000254 GrContext* context,
255 const GrDrawTargetCaps&,
256 GrTexture* textures[]) {
257 return GrRectEffect::Create();
258}
259
260///////////////////////////////////////////////////////////////////////////////
261
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000262namespace {
263
robertphillips@google.com42903302013-04-20 12:26:07 +0000264extern const GrVertexAttrib gAARectCoverageAttribs[] = {
265 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
266 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
267};
268
269extern const GrVertexAttrib gAARectColorAttribs[] = {
270 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
271 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
272};
273
274static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
275 if (useCoverage) {
276 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
277 } else {
278 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
279 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000280}
281
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000282static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000283 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000284 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
285 r.fRight - dx, r.fBottom - dy, stride);
286}
287
288};
289
290void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000291 SkSafeSetNull(fAAFillRectIndexBuffer);
292 SkSafeSetNull(fAAStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000293}
294
robertphillips@google.com6d067302012-12-18 21:47:47 +0000295static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296 0, 1, 5, 5, 4, 0,
297 1, 2, 6, 6, 5, 1,
298 2, 3, 7, 7, 6, 2,
299 3, 0, 4, 4, 7, 3,
300 4, 5, 6, 6, 7, 4,
301};
302
robertphillips@google.com6d067302012-12-18 21:47:47 +0000303static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
304static const int kVertsPerAAFillRect = 8;
305static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000306
307GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000308 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
309 sizeof(uint16_t) *
310 kNumAAFillRectsInIndexBuffer;
311
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000312 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000313 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000314 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000315 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
316 bool useTempData = (NULL == data);
317 if (useTempData) {
318 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
319 }
320 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
321 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
322 // the inner rect (for AA) and 2 for the inner rect.
323 int baseIdx = i * kIndicesPerAAFillRect;
324 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
325 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
326 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
327 }
328 }
329 if (useTempData) {
330 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
331 GrCrash("Can't get AA Fill Rect indices into buffer!");
332 }
333 SkDELETE_ARRAY(data);
334 } else {
335 fAAFillRectIndexBuffer->unlock();
336 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000337 }
338 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000339
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000340 return fAAFillRectIndexBuffer;
341}
342
robertphillips@google.com6d067302012-12-18 21:47:47 +0000343static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000344 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
345 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
346 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
347 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
348
349 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
350 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
351 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
352 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
353
354 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
355 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
356 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
357 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
358};
359
360int GrAARectRenderer::aaStrokeRectIndexCount() {
361 return GR_ARRAY_COUNT(gStrokeAARectIdx);
362}
363
364GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
365 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000366 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000367 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
368 if (NULL != fAAStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000369#ifdef SK_DEBUG
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000370 bool updated =
371#endif
372 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
373 sizeof(gStrokeAARectIdx));
374 GR_DEBUGASSERT(updated);
375 }
376 }
377 return fAAStrokeRectIndexBuffer;
378}
379
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000380void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
381 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000382 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000383 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000384 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000385 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000386 GrDrawState* drawState = target->drawState();
387
robertphillips@google.com42903302013-04-20 12:26:07 +0000388 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000389
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000390 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000391 if (!geo.succeeded()) {
392 GrPrintf("Failed to get space for vertices!\n");
393 return;
394 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000395
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000396 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
397 if (NULL == indexBuffer) {
398 GrPrintf("Failed to create index buffer!\n");
399 return;
400 }
401
402 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000403 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000404 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000405
406 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
407 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
408
robertphillips@google.com908aed82013-05-28 13:16:20 +0000409 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
410 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
411
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000412 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000413 // Temporarily #if'ed out. We don't want to pass in the devRect but
414 // right now it is computed in GrContext::apply_aa_to_rect and we don't
415 // want to throw away the work
416#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000417 SkRect devRect;
418 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000419#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000420
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000421 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000422 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000423 } else {
424 // compute transformed (1, 0) and (0, 1) vectors
425 SkVector vec[2] = {
426 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
427 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
428 };
429
430 vec[0].normalize();
431 vec[0].scale(SK_ScalarHalf);
432 vec[1].normalize();
433 vec[1].scale(SK_ScalarHalf);
434
robertphillips@google.com91b71162013-05-10 14:09:54 +0000435 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000436 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
437 rect.fRight, rect.fBottom, vsize);
438 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
439
robertphillips@google.com91b71162013-05-10 14:09:54 +0000440 // Now create the inset points and then outset the original
441 // rotated points
442
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000443 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000444 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000445 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
446 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
447 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000448 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000449 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
450 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
451 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000452 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000453 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
454 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
455 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000456 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000457 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
458 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
459 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000460
461 verts += sizeof(GrPoint);
462 for (int i = 0; i < 4; ++i) {
463 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
464 }
465
robertphillips@google.com908aed82013-05-28 13:16:20 +0000466 int scale;
467 if (inset < SK_ScalarHalf) {
468 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
469 SkASSERT(scale >= 0 && scale <= 255);
470 } else {
471 scale = 0xff;
472 }
473
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000474 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000475 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000476 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000477 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000478 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000479 innerColor = target->getDrawState().getColor();
480 } else {
481 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
482 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000483 }
484
485 verts += 4 * vsize;
486 for (int i = 0; i < 4; ++i) {
487 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
488 }
489
490 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000491 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
492 kVertsPerAAFillRect,
493 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000494 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000495}
496
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000497namespace {
498
499// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000500struct RectVertex {
501 GrPoint fPos;
502 GrPoint fCenter;
503 GrPoint fDir;
504 GrPoint fWidthHeight;
505};
506
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000507// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000508extern const GrVertexAttrib gAARectVertexAttribs[] = {
509 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
510 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
511 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
512};
513
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000514// Axis Aligned
515struct AARectVertex {
516 GrPoint fPos;
517 GrPoint fOffset;
518 GrPoint fWidthHeight;
519};
520
521// Axis Aligned
522extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
523 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
524 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
525};
526
robertphillips@google.com42903302013-04-20 12:26:07 +0000527};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000528
529void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
530 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000531 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000532 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000533 GrDrawState* drawState = target->drawState();
534
535 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
536 combinedMatrix.mapPoints(&center, 1);
537
538 // compute transformed (0, 1) vector
539 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
540 dir.normalize();
541
542 // compute transformed (width, 0) and (0, height) vectors
543 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000544 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
545 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000546 };
547
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000548 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
549 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000550 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000551 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000552
553 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
554 if (!geo.succeeded()) {
555 GrPrintf("Failed to get space for vertices!\n");
556 return;
557 }
558
559 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
560
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000561 GrEffectRef* effect = GrRectEffect::Create();
562 static const int kRectAttrIndex = 1;
563 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000564 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000565
566 for (int i = 0; i < 4; ++i) {
567 verts[i].fCenter = center;
568 verts[i].fDir = dir;
569 verts[i].fWidthHeight.fX = newWidth;
570 verts[i].fWidthHeight.fY = newHeight;
571 }
572
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000573 SkRect devRect;
574 combinedMatrix.mapRect(&devRect, rect);
575
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000576 SkRect devBounds = {
577 devRect.fLeft - SK_ScalarHalf,
578 devRect.fTop - SK_ScalarHalf,
579 devRect.fRight + SK_ScalarHalf,
580 devRect.fBottom + SK_ScalarHalf
581 };
582
583 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
584 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
585 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
586 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
587
588 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
589 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
590 target->resetIndexSource();
591}
592
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000593void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
594 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000595 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000596 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000597 GrDrawState* drawState = target->drawState();
598 SkASSERT(combinedMatrix.rectStaysRect());
599
600 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000601 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000602
603 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
604 if (!geo.succeeded()) {
605 GrPrintf("Failed to get space for vertices!\n");
606 return;
607 }
608
609 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
610
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000611 GrEffectRef* effect = GrAlignedRectEffect::Create();
612 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000613 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000614
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000615 SkRect devRect;
616 combinedMatrix.mapRect(&devRect, rect);
617
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000618 SkRect devBounds = {
619 devRect.fLeft - SK_ScalarHalf,
620 devRect.fTop - SK_ScalarHalf,
621 devRect.fRight + SK_ScalarHalf,
622 devRect.fBottom + SK_ScalarHalf
623 };
624
625 GrPoint widthHeight = {
626 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
627 SkScalarHalf(devRect.height()) + SK_ScalarHalf
628 };
629
630 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
631 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
632 verts[0].fWidthHeight = widthHeight;
633
634 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
635 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
636 verts[1].fWidthHeight = widthHeight;
637
638 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
639 verts[2].fOffset = widthHeight;
640 verts[2].fWidthHeight = widthHeight;
641
642 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
643 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
644 verts[3].fWidthHeight = widthHeight;
645
646 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
647 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
648 target->resetIndexSource();
649}
650
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000651void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000652 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000653 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000654 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000655 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000656 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000657 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000658 GrVec devStrokeSize;
659 if (width > 0) {
660 devStrokeSize.set(width, width);
661 combinedMatrix.mapVectors(&devStrokeSize, 1);
662 devStrokeSize.setAbs(devStrokeSize);
663 } else {
664 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
665 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000666
robertphillips@google.com18136d12013-05-10 11:05:58 +0000667 const SkScalar dx = devStrokeSize.fX;
668 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000669 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
670 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000671
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000672 // Temporarily #if'ed out. We don't want to pass in the devRect but
673 // right now it is computed in GrContext::apply_aa_to_rect and we don't
674 // want to throw away the work
675#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000676 SkRect devRect;
677 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000678#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000679
bsalomon@google.com81712882012-11-01 17:12:34 +0000680 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000681 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000682 SkScalar w = devRect.width() - dx;
683 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000684 spare = GrMin(w, h);
685 }
686
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000687 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000688 devOutside.outset(rx, ry);
689
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000690 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000691 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000692 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000693 return;
694 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000695
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000696 SkRect devInside(devRect);
697 devInside.inset(rx, ry);
698
699 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
700}
701
702void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
703 GrDrawTarget* target,
704 const SkRect& devOutside,
705 const SkRect& devInside,
706 bool useVertexCoverage) {
707 GrDrawState* drawState = target->drawState();
708
robertphillips@google.com42903302013-04-20 12:26:07 +0000709 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000710
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000711 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000712 if (!geo.succeeded()) {
713 GrPrintf("Failed to get space for vertices!\n");
714 return;
715 }
716 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
717 if (NULL == indexBuffer) {
718 GrPrintf("Failed to create index buffer!\n");
719 return;
720 }
721
722 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000723 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000724 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000725
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000726 // We create vertices for four nested rectangles. There are two ramps from 0 to full
727 // coverage, one on the exterior of the stroke and the other on the interior.
728 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000729 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
730 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
731 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
732 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
733
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000734#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000735 // TODO: this only really works if the X & Y margins are the same all around
736 // the rect
737 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
738 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
739 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
740 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
741 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000742#else
743 SkScalar inset = SK_ScalarHalf;
744#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000745
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000746 // outermost
747 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000748 // inner two
749 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
750 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000751 // innermost
752 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000753
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000754 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000755 verts += sizeof(GrPoint);
756 for (int i = 0; i < 4; ++i) {
757 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
758 }
759
robertphillips@google.com353f0972013-06-28 17:57:06 +0000760 int scale;
761 if (inset < SK_ScalarHalf) {
762 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
763 SkASSERT(scale >= 0 && scale <= 255);
764 } else {
765 scale = 0xff;
766 }
767
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000768 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000769 GrColor innerColor;
770 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000771 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000772 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000773 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000774 innerColor = target->getDrawState().getColor();
775 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000776 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
777 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000778 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000779
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000780 verts += 4 * vsize;
781 for (int i = 0; i < 8; ++i) {
782 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
783 }
784
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000785 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000786 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000787 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000788 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
789 }
790
791 target->setIndexSourceToBuffer(indexBuffer);
792 target->drawIndexed(kTriangles_GrPrimitiveType,
793 0, 0, 16, aaStrokeRectIndexCount());
794}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000795
796void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
797 GrDrawTarget* target,
798 const SkRect rects[2],
799 const SkMatrix& combinedMatrix,
800 bool useVertexCoverage) {
801 SkASSERT(combinedMatrix.rectStaysRect());
802 SkASSERT(!rects[1].isEmpty());
803
804 SkRect devOutside, devInside;
805 combinedMatrix.mapRect(&devOutside, rects[0]);
806 // can't call mapRect for devInside since it calls sort
807 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
808
809 if (devInside.isEmpty()) {
810 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
811 return;
812 }
813
814 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
815}