blob: 4856bb54188139ed2945955e1e56f1fe1d9adf0e [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
46 virtual void emitCode(GrGLShaderBuilder* builder,
47 const GrDrawEffect& drawEffect,
48 EffectKey key,
49 const char* outputColor,
50 const char* inputColor,
51 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000052 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
53 SkASSERT(NULL != vertexBuilder);
54
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000055 // 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.org5a02cb42013-08-30 20:17:31 +000059 vertexBuilder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000060 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000061 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
62 vertexBuilder->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:
99 typedef GrGLEffect INHERITED;
100 };
101
102
103private:
104 GrAlignedRectEffect() : GrEffect() {
105 this->addVertexAttrib(kVec4f_GrSLType);
106 }
107
108 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
109
110 GR_DECLARE_EFFECT_TEST;
111
112 typedef GrEffect INHERITED;
113};
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 */
140class GrRectEffect : public GrEffect {
141public:
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
161 class GLEffect : public GrGLEffect {
162 public:
163 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
164 : INHERITED (factory) {}
165
166 virtual void emitCode(GrGLShaderBuilder* builder,
167 const GrDrawEffect& drawEffect,
168 EffectKey key,
169 const char* outputColor,
170 const char* inputColor,
171 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000172 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
173 SkASSERT(NULL != vertexBuilder);
174
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000175 // setup the varying for the center point and the unit vector
176 // that points down the height of the rect
177 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000178 vertexBuilder->addVarying(kVec4f_GrSLType, "RectEdge",
179 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000180 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000181 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
182 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000183
184 // setup the varying for width/2+.5 and height/2+.5
185 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000186 vertexBuilder->addVarying(kVec2f_GrSLType, "WidthHeight",
187 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000188 const SkString* attr1Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000189 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
190 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000191
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000192 // TODO: compute all these offsets, spans, and scales in the VS
193 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
194 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
195 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
196 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
197 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
198 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
199 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
200 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
201 // value of coverage that is used. In other words it is the coverage that is
202 // used in the interior of the rect after the ramp.
203 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
204 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000205
206 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000207 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000208 builder->fragmentPosition(), fsRectEdgeName);
209 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
210 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000211 builder->fsCodeAppendf(
212 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
213 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000214
215 // Compute the coverage for the rect's height and merge with the width
216 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
217 fsRectEdgeName);
218 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000219 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000220 fsWidthHeightName);
221
222 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000223 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000224 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
225 }
226
227 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
228 return 0;
229 }
230
231 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
232
233 private:
234 typedef GrGLEffect INHERITED;
235 };
236
237
238private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000239 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000240 this->addVertexAttrib(kVec4f_GrSLType);
241 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000242 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000243 }
244
245 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
246
247 GR_DECLARE_EFFECT_TEST;
248
249 typedef GrEffect INHERITED;
250};
251
252
253GR_DEFINE_EFFECT_TEST(GrRectEffect);
254
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000255GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000256 GrContext* context,
257 const GrDrawTargetCaps&,
258 GrTexture* textures[]) {
259 return GrRectEffect::Create();
260}
261
262///////////////////////////////////////////////////////////////////////////////
263
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000264namespace {
265
robertphillips@google.com42903302013-04-20 12:26:07 +0000266extern const GrVertexAttrib gAARectCoverageAttribs[] = {
267 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
268 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
269};
270
271extern const GrVertexAttrib gAARectColorAttribs[] = {
272 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
273 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
274};
275
276static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
277 if (useCoverage) {
278 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
279 } else {
280 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
281 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000282}
283
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000284static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000285 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000286 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
287 r.fRight - dx, r.fBottom - dy, stride);
288}
289
290};
291
292void GrAARectRenderer::reset() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000293 SkSafeSetNull(fAAFillRectIndexBuffer);
294 SkSafeSetNull(fAAStrokeRectIndexBuffer);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000295}
296
robertphillips@google.com6d067302012-12-18 21:47:47 +0000297static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000298 0, 1, 5, 5, 4, 0,
299 1, 2, 6, 6, 5, 1,
300 2, 3, 7, 7, 6, 2,
301 3, 0, 4, 4, 7, 3,
302 4, 5, 6, 6, 7, 4,
303};
304
robertphillips@google.com6d067302012-12-18 21:47:47 +0000305static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
306static const int kVertsPerAAFillRect = 8;
307static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000308
309GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000310 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
311 sizeof(uint16_t) *
312 kNumAAFillRectsInIndexBuffer;
313
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000314 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000315 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000316 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000317 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
318 bool useTempData = (NULL == data);
319 if (useTempData) {
320 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
321 }
322 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
323 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
324 // the inner rect (for AA) and 2 for the inner rect.
325 int baseIdx = i * kIndicesPerAAFillRect;
326 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
327 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
328 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
329 }
330 }
331 if (useTempData) {
332 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
333 GrCrash("Can't get AA Fill Rect indices into buffer!");
334 }
335 SkDELETE_ARRAY(data);
336 } else {
337 fAAFillRectIndexBuffer->unlock();
338 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000339 }
340 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000341
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000342 return fAAFillRectIndexBuffer;
343}
344
robertphillips@google.com6d067302012-12-18 21:47:47 +0000345static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000346 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
347 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
348 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
349 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
350
351 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
352 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
353 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
354 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
355
356 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
357 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
358 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
359 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
360};
361
362int GrAARectRenderer::aaStrokeRectIndexCount() {
363 return GR_ARRAY_COUNT(gStrokeAARectIdx);
364}
365
366GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
367 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000368 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000369 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
370 if (NULL != fAAStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000371#ifdef SK_DEBUG
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000372 bool updated =
373#endif
374 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
375 sizeof(gStrokeAARectIdx));
376 GR_DEBUGASSERT(updated);
377 }
378 }
379 return fAAStrokeRectIndexBuffer;
380}
381
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000382void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
383 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000384 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000385 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000386 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000387 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000388 GrDrawState* drawState = target->drawState();
389
robertphillips@google.com42903302013-04-20 12:26:07 +0000390 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000391
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000392 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000393 if (!geo.succeeded()) {
394 GrPrintf("Failed to get space for vertices!\n");
395 return;
396 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000397
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000398 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
399 if (NULL == indexBuffer) {
400 GrPrintf("Failed to create index buffer!\n");
401 return;
402 }
403
404 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000405 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000406 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000407
408 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
409 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
410
robertphillips@google.com908aed82013-05-28 13:16:20 +0000411 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
412 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
413
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000414 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000415 // Temporarily #if'ed out. We don't want to pass in the devRect but
416 // right now it is computed in GrContext::apply_aa_to_rect and we don't
417 // want to throw away the work
418#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000419 SkRect devRect;
420 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000421#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000422
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000423 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000424 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000425 } else {
426 // compute transformed (1, 0) and (0, 1) vectors
427 SkVector vec[2] = {
428 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
429 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
430 };
431
432 vec[0].normalize();
433 vec[0].scale(SK_ScalarHalf);
434 vec[1].normalize();
435 vec[1].scale(SK_ScalarHalf);
436
robertphillips@google.com91b71162013-05-10 14:09:54 +0000437 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000438 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
439 rect.fRight, rect.fBottom, vsize);
440 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
441
robertphillips@google.com91b71162013-05-10 14:09:54 +0000442 // Now create the inset points and then outset the original
443 // rotated points
444
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000445 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000446 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000447 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
448 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
449 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000450 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000451 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
452 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
453 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000454 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000455 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
456 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
457 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000458 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000459 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
460 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
461 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000462
463 verts += sizeof(GrPoint);
464 for (int i = 0; i < 4; ++i) {
465 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
466 }
467
robertphillips@google.com908aed82013-05-28 13:16:20 +0000468 int scale;
469 if (inset < SK_ScalarHalf) {
470 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
471 SkASSERT(scale >= 0 && scale <= 255);
472 } else {
473 scale = 0xff;
474 }
475
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000476 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000477 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000478 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000479 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000480 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000481 innerColor = target->getDrawState().getColor();
482 } else {
483 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
484 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000485 }
486
487 verts += 4 * vsize;
488 for (int i = 0; i < 4; ++i) {
489 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
490 }
491
492 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000493 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
494 kVertsPerAAFillRect,
495 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000496 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000497}
498
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000499namespace {
500
501// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000502struct RectVertex {
503 GrPoint fPos;
504 GrPoint fCenter;
505 GrPoint fDir;
506 GrPoint fWidthHeight;
507};
508
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000509// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000510extern const GrVertexAttrib gAARectVertexAttribs[] = {
511 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
512 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
513 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
514};
515
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000516// Axis Aligned
517struct AARectVertex {
518 GrPoint fPos;
519 GrPoint fOffset;
520 GrPoint fWidthHeight;
521};
522
523// Axis Aligned
524extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
525 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
526 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
527};
528
robertphillips@google.com42903302013-04-20 12:26:07 +0000529};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000530
531void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
532 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000533 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000534 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000535 GrDrawState* drawState = target->drawState();
536
537 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
538 combinedMatrix.mapPoints(&center, 1);
539
540 // compute transformed (0, 1) vector
541 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
542 dir.normalize();
543
544 // compute transformed (width, 0) and (0, height) vectors
545 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000546 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
547 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000548 };
549
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000550 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
551 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000552 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000553 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000554
555 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
556 if (!geo.succeeded()) {
557 GrPrintf("Failed to get space for vertices!\n");
558 return;
559 }
560
561 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
562
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000563 GrEffectRef* effect = GrRectEffect::Create();
564 static const int kRectAttrIndex = 1;
565 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000566 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000567
568 for (int i = 0; i < 4; ++i) {
569 verts[i].fCenter = center;
570 verts[i].fDir = dir;
571 verts[i].fWidthHeight.fX = newWidth;
572 verts[i].fWidthHeight.fY = newHeight;
573 }
574
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000575 SkRect devRect;
576 combinedMatrix.mapRect(&devRect, rect);
577
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000578 SkRect devBounds = {
579 devRect.fLeft - SK_ScalarHalf,
580 devRect.fTop - SK_ScalarHalf,
581 devRect.fRight + SK_ScalarHalf,
582 devRect.fBottom + SK_ScalarHalf
583 };
584
585 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
586 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
587 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
588 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
589
590 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
591 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
592 target->resetIndexSource();
593}
594
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000595void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
596 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000597 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000598 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000599 GrDrawState* drawState = target->drawState();
600 SkASSERT(combinedMatrix.rectStaysRect());
601
602 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000603 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000604
605 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
606 if (!geo.succeeded()) {
607 GrPrintf("Failed to get space for vertices!\n");
608 return;
609 }
610
611 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
612
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000613 GrEffectRef* effect = GrAlignedRectEffect::Create();
614 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000615 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000616
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000617 SkRect devRect;
618 combinedMatrix.mapRect(&devRect, rect);
619
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000620 SkRect devBounds = {
621 devRect.fLeft - SK_ScalarHalf,
622 devRect.fTop - SK_ScalarHalf,
623 devRect.fRight + SK_ScalarHalf,
624 devRect.fBottom + SK_ScalarHalf
625 };
626
627 GrPoint widthHeight = {
628 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
629 SkScalarHalf(devRect.height()) + SK_ScalarHalf
630 };
631
632 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
633 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
634 verts[0].fWidthHeight = widthHeight;
635
636 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
637 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
638 verts[1].fWidthHeight = widthHeight;
639
640 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
641 verts[2].fOffset = widthHeight;
642 verts[2].fWidthHeight = widthHeight;
643
644 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
645 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
646 verts[3].fWidthHeight = widthHeight;
647
648 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
649 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
650 target->resetIndexSource();
651}
652
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000653void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000654 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000655 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000656 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000657 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000658 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000659 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000660 GrVec devStrokeSize;
661 if (width > 0) {
662 devStrokeSize.set(width, width);
663 combinedMatrix.mapVectors(&devStrokeSize, 1);
664 devStrokeSize.setAbs(devStrokeSize);
665 } else {
666 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
667 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000668
robertphillips@google.com18136d12013-05-10 11:05:58 +0000669 const SkScalar dx = devStrokeSize.fX;
670 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000671 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
672 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000673
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000674 // Temporarily #if'ed out. We don't want to pass in the devRect but
675 // right now it is computed in GrContext::apply_aa_to_rect and we don't
676 // want to throw away the work
677#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000678 SkRect devRect;
679 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000680#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000681
bsalomon@google.com81712882012-11-01 17:12:34 +0000682 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000683 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000684 SkScalar w = devRect.width() - dx;
685 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000686 spare = GrMin(w, h);
687 }
688
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000689 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000690 devOutside.outset(rx, ry);
691
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000692 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000693 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000694 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000695 return;
696 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000697
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000698 SkRect devInside(devRect);
699 devInside.inset(rx, ry);
700
701 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
702}
703
704void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
705 GrDrawTarget* target,
706 const SkRect& devOutside,
707 const SkRect& devInside,
708 bool useVertexCoverage) {
709 GrDrawState* drawState = target->drawState();
710
robertphillips@google.com42903302013-04-20 12:26:07 +0000711 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000712
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000713 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000714 if (!geo.succeeded()) {
715 GrPrintf("Failed to get space for vertices!\n");
716 return;
717 }
718 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
719 if (NULL == indexBuffer) {
720 GrPrintf("Failed to create index buffer!\n");
721 return;
722 }
723
724 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000725 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000726 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000727
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000728 // We create vertices for four nested rectangles. There are two ramps from 0 to full
729 // coverage, one on the exterior of the stroke and the other on the interior.
730 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000731 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
732 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
733 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
734 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
735
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000736#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000737 // TODO: this only really works if the X & Y margins are the same all around
738 // the rect
739 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
740 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
741 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
742 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
743 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000744#else
745 SkScalar inset = SK_ScalarHalf;
746#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000747
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000748 // outermost
749 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000750 // inner two
751 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
752 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000753 // innermost
754 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000755
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000756 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000757 verts += sizeof(GrPoint);
758 for (int i = 0; i < 4; ++i) {
759 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
760 }
761
robertphillips@google.com353f0972013-06-28 17:57:06 +0000762 int scale;
763 if (inset < SK_ScalarHalf) {
764 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
765 SkASSERT(scale >= 0 && scale <= 255);
766 } else {
767 scale = 0xff;
768 }
769
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000770 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000771 GrColor innerColor;
772 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000773 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000774 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000775 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000776 innerColor = target->getDrawState().getColor();
777 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000778 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
779 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000780 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000781
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000782 verts += 4 * vsize;
783 for (int i = 0; i < 8; ++i) {
784 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
785 }
786
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000787 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000788 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000789 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000790 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
791 }
792
793 target->setIndexSourceToBuffer(indexBuffer);
794 target->drawIndexed(kTriangles_GrPrimitiveType,
795 0, 0, 16, aaStrokeRectIndexCount());
796}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000797
798void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
799 GrDrawTarget* target,
800 const SkRect rects[2],
801 const SkMatrix& combinedMatrix,
802 bool useVertexCoverage) {
803 SkASSERT(combinedMatrix.rectStaysRect());
804 SkASSERT(!rects[1].isEmpty());
805
806 SkRect devOutside, devInside;
807 combinedMatrix.mapRect(&devOutside, rects[0]);
808 // can't call mapRect for devInside since it calls sort
809 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
810
811 if (devInside.isEmpty()) {
812 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
813 return;
814 }
815
816 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
817}