blob: b104df5d24a7576053277be370c4adacc5f03e44 [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"
9#include "GrRefCnt.h"
10#include "GrGpu.h"
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000011#include "gl/GrGLEffect.h"
12#include "GrTBackendEffectFactory.h"
robertphillips@google.com908aed82013-05-28 13:16:20 +000013#include "SkColorPriv.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
21class GrAlignedRectEffect : public GrEffect {
22public:
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
commit-bot@chromium.orga91f0312013-09-06 20:19:56 +000047 virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
48
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000049 virtual void emitCode(GrGLShaderBuilder* builder,
50 const GrDrawEffect& drawEffect,
51 EffectKey key,
52 const char* outputColor,
53 const char* inputColor,
54 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000055 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
56 SkASSERT(NULL != vertexBuilder);
57
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000058 // setup the varying for the Axis aligned rect effect
59 // xy -> interpolated offset
60 // zw -> w/2+0.5, h/2+0.5
61 const char *vsRectName, *fsRectName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000062 vertexBuilder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000063 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +000064 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
65 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000066
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000067 // TODO: compute all these offsets, spans, and scales in the VS
68 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
69 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
70 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
71 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
72 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
73 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
74 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
75 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
76 // value of coverage that is used. In other words it is the coverage that is
77 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000078 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
79 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000080
81 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000082 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000083 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
84 fsRectName);
85 // Compute the coverage for the rect's height and merge with the width
egdaniel@google.comf1d7de72013-06-14 19:25:53 +000086 builder->fsCodeAppendf(
87 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
88 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000089
90 SkString modulate;
91 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
92 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
93 }
94
95 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
96 return 0;
97 }
98
99 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
100
101 private:
102 typedef GrGLEffect INHERITED;
103 };
104
105
106private:
107 GrAlignedRectEffect() : GrEffect() {
108 this->addVertexAttrib(kVec4f_GrSLType);
109 }
110
111 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
112
113 GR_DECLARE_EFFECT_TEST;
114
115 typedef GrEffect INHERITED;
116};
117
118
119GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
120
121GrEffectRef* GrAlignedRectEffect::TestCreate(SkMWCRandom* random,
122 GrContext* context,
123 const GrDrawTargetCaps&,
124 GrTexture* textures[]) {
125 return GrAlignedRectEffect::Create();
126}
127
128///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000129class GrGLRectEffect;
130
131/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000132 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000133 * for an arbitrarily oriented rect. The rect is specified as:
134 * Center of the rect
135 * Unit vector point down the height of the rect
136 * Half width + 0.5
137 * Half height + 0.5
138 * The center and vector are stored in a vec4 varying ("RectEdge") with the
139 * center in the xy components and the vector in the zw components.
140 * The munged width and height are stored in a vec2 varying ("WidthHeight")
141 * with the width in x and the height in y.
142 */
143class GrRectEffect : public GrEffect {
144public:
145 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000146 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
147 gRectEffect->ref();
148 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000149 }
150
151 virtual ~GrRectEffect() {}
152
153 static const char* Name() { return "RectEdge"; }
154
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000155 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000156 uint32_t* validFlags) const SK_OVERRIDE {
157 *validFlags = 0;
158 }
159
160 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
161 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
162 }
163
164 class GLEffect : public GrGLEffect {
165 public:
166 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
167 : INHERITED (factory) {}
168
commit-bot@chromium.orga91f0312013-09-06 20:19:56 +0000169 virtual bool requiresVertexShader(const GrDrawEffect&) const SK_OVERRIDE { return true; }
170
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000171 virtual void emitCode(GrGLShaderBuilder* builder,
172 const GrDrawEffect& drawEffect,
173 EffectKey key,
174 const char* outputColor,
175 const char* inputColor,
176 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000177 GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
178 SkASSERT(NULL != vertexBuilder);
179
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000180 // setup the varying for the center point and the unit vector
181 // that points down the height of the rect
182 const char *vsRectEdgeName, *fsRectEdgeName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000183 vertexBuilder->addVarying(kVec4f_GrSLType, "RectEdge",
184 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000185 const SkString* attr0Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000186 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
187 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000188
189 // setup the varying for width/2+.5 and height/2+.5
190 const char *vsWidthHeightName, *fsWidthHeightName;
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000191 vertexBuilder->addVarying(kVec2f_GrSLType, "WidthHeight",
192 &vsWidthHeightName, &fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000193 const SkString* attr1Name =
commit-bot@chromium.org5a02cb42013-08-30 20:17:31 +0000194 vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
195 vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000196
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000197 // TODO: compute all these offsets, spans, and scales in the VS
198 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
199 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
200 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
201 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
202 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
203 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
204 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
205 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
206 // value of coverage that is used. In other words it is the coverage that is
207 // used in the interior of the rect after the ramp.
208 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
209 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000210
211 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000212 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000213 builder->fragmentPosition(), fsRectEdgeName);
214 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
215 fsRectEdgeName, fsRectEdgeName);
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000216 builder->fsCodeAppendf(
217 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
218 fsWidthHeightName);
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000219
220 // Compute the coverage for the rect's height and merge with the width
221 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
222 fsRectEdgeName);
223 builder->fsCodeAppendf(
egdaniel@google.comf1d7de72013-06-14 19:25:53 +0000224 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000225 fsWidthHeightName);
226
227 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000228 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000229 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
230 }
231
232 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
233 return 0;
234 }
235
236 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
237
238 private:
239 typedef GrGLEffect INHERITED;
240 };
241
242
243private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000244 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000245 this->addVertexAttrib(kVec4f_GrSLType);
246 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000247 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000248 }
249
250 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
251
252 GR_DECLARE_EFFECT_TEST;
253
254 typedef GrEffect INHERITED;
255};
256
257
258GR_DEFINE_EFFECT_TEST(GrRectEffect);
259
260GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
261 GrContext* context,
262 const GrDrawTargetCaps&,
263 GrTexture* textures[]) {
264 return GrRectEffect::Create();
265}
266
267///////////////////////////////////////////////////////////////////////////////
268
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000269namespace {
270
robertphillips@google.com42903302013-04-20 12:26:07 +0000271extern const GrVertexAttrib gAARectCoverageAttribs[] = {
272 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
273 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
274};
275
276extern const GrVertexAttrib gAARectColorAttribs[] = {
277 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
278 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
279};
280
281static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
282 if (useCoverage) {
283 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
284 } else {
285 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
286 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000287}
288
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000289static void set_inset_fan(GrPoint* pts, size_t stride,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000290 const SkRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000291 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
292 r.fRight - dx, r.fBottom - dy, stride);
293}
294
295};
296
297void GrAARectRenderer::reset() {
298 GrSafeSetNull(fAAFillRectIndexBuffer);
299 GrSafeSetNull(fAAStrokeRectIndexBuffer);
300}
301
robertphillips@google.com6d067302012-12-18 21:47:47 +0000302static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000303 0, 1, 5, 5, 4, 0,
304 1, 2, 6, 6, 5, 1,
305 2, 3, 7, 7, 6, 2,
306 3, 0, 4, 4, 7, 3,
307 4, 5, 6, 6, 7, 4,
308};
309
robertphillips@google.com6d067302012-12-18 21:47:47 +0000310static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
311static const int kVertsPerAAFillRect = 8;
312static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000313
314GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000315 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
316 sizeof(uint16_t) *
317 kNumAAFillRectsInIndexBuffer;
318
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000319 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000320 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000321 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000322 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
323 bool useTempData = (NULL == data);
324 if (useTempData) {
325 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
326 }
327 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
328 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
329 // the inner rect (for AA) and 2 for the inner rect.
330 int baseIdx = i * kIndicesPerAAFillRect;
331 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
332 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
333 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
334 }
335 }
336 if (useTempData) {
337 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
338 GrCrash("Can't get AA Fill Rect indices into buffer!");
339 }
340 SkDELETE_ARRAY(data);
341 } else {
342 fAAFillRectIndexBuffer->unlock();
343 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000344 }
345 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000346
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000347 return fAAFillRectIndexBuffer;
348}
349
robertphillips@google.com6d067302012-12-18 21:47:47 +0000350static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000351 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
352 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
353 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
354 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
355
356 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
357 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
358 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
359 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
360
361 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
362 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
363 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
364 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
365};
366
367int GrAARectRenderer::aaStrokeRectIndexCount() {
368 return GR_ARRAY_COUNT(gStrokeAARectIdx);
369}
370
371GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
372 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000373 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000374 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
375 if (NULL != fAAStrokeRectIndexBuffer) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000376#ifdef SK_DEBUG
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000377 bool updated =
378#endif
379 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
380 sizeof(gStrokeAARectIdx));
381 GR_DEBUGASSERT(updated);
382 }
383 }
384 return fAAStrokeRectIndexBuffer;
385}
386
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000387void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
388 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000389 const SkRect& rect,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000390 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000391 const SkRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000392 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000393 GrDrawState* drawState = target->drawState();
394
robertphillips@google.com42903302013-04-20 12:26:07 +0000395 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000396
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000397 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000398 if (!geo.succeeded()) {
399 GrPrintf("Failed to get space for vertices!\n");
400 return;
401 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000402
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000403 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
404 if (NULL == indexBuffer) {
405 GrPrintf("Failed to create index buffer!\n");
406 return;
407 }
408
409 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000410 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000411 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000412
413 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
414 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
415
robertphillips@google.com908aed82013-05-28 13:16:20 +0000416 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
417 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
418
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000419 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000420 // Temporarily #if'ed out. We don't want to pass in the devRect but
421 // right now it is computed in GrContext::apply_aa_to_rect and we don't
422 // want to throw away the work
423#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000424 SkRect devRect;
425 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000426#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000427
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000428 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000429 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000430 } else {
431 // compute transformed (1, 0) and (0, 1) vectors
432 SkVector vec[2] = {
433 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
434 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
435 };
436
437 vec[0].normalize();
438 vec[0].scale(SK_ScalarHalf);
439 vec[1].normalize();
440 vec[1].scale(SK_ScalarHalf);
441
robertphillips@google.com91b71162013-05-10 14:09:54 +0000442 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000443 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
444 rect.fRight, rect.fBottom, vsize);
445 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
446
robertphillips@google.com91b71162013-05-10 14:09:54 +0000447 // Now create the inset points and then outset the original
448 // rotated points
449
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000450 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000451 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000452 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
453 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
454 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000455 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000456 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
457 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
458 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000459 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000460 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
461 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
462 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000463 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000464 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
465 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
466 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000467
468 verts += sizeof(GrPoint);
469 for (int i = 0; i < 4; ++i) {
470 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
471 }
472
robertphillips@google.com908aed82013-05-28 13:16:20 +0000473 int scale;
474 if (inset < SK_ScalarHalf) {
475 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
476 SkASSERT(scale >= 0 && scale <= 255);
477 } else {
478 scale = 0xff;
479 }
480
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000481 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000482 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000483 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000484 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000485 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000486 innerColor = target->getDrawState().getColor();
487 } else {
488 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
489 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000490 }
491
492 verts += 4 * vsize;
493 for (int i = 0; i < 4; ++i) {
494 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
495 }
496
497 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000498 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
499 kVertsPerAAFillRect,
500 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000501 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000502}
503
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000504namespace {
505
506// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000507struct RectVertex {
508 GrPoint fPos;
509 GrPoint fCenter;
510 GrPoint fDir;
511 GrPoint fWidthHeight;
512};
513
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000514// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000515extern const GrVertexAttrib gAARectVertexAttribs[] = {
516 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
517 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
518 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
519};
520
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000521// Axis Aligned
522struct AARectVertex {
523 GrPoint fPos;
524 GrPoint fOffset;
525 GrPoint fWidthHeight;
526};
527
528// Axis Aligned
529extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
530 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
531 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
532};
533
robertphillips@google.com42903302013-04-20 12:26:07 +0000534};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000535
536void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
537 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000538 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000539 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000540 GrDrawState* drawState = target->drawState();
541
542 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
543 combinedMatrix.mapPoints(&center, 1);
544
545 // compute transformed (0, 1) vector
546 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
547 dir.normalize();
548
549 // compute transformed (width, 0) and (0, height) vectors
550 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000551 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
552 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000553 };
554
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000555 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
556 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000557 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000558 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000559
560 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
561 if (!geo.succeeded()) {
562 GrPrintf("Failed to get space for vertices!\n");
563 return;
564 }
565
566 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
567
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000568 GrEffectRef* effect = GrRectEffect::Create();
569 static const int kRectAttrIndex = 1;
570 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000571 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000572
573 for (int i = 0; i < 4; ++i) {
574 verts[i].fCenter = center;
575 verts[i].fDir = dir;
576 verts[i].fWidthHeight.fX = newWidth;
577 verts[i].fWidthHeight.fY = newHeight;
578 }
579
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000580 SkRect devRect;
581 combinedMatrix.mapRect(&devRect, rect);
582
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000583 SkRect devBounds = {
584 devRect.fLeft - SK_ScalarHalf,
585 devRect.fTop - SK_ScalarHalf,
586 devRect.fRight + SK_ScalarHalf,
587 devRect.fBottom + SK_ScalarHalf
588 };
589
590 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
591 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
592 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
593 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
594
595 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
596 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
597 target->resetIndexSource();
598}
599
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000600void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
601 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000602 const SkRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000603 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000604 GrDrawState* drawState = target->drawState();
605 SkASSERT(combinedMatrix.rectStaysRect());
606
607 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000608 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000609
610 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
611 if (!geo.succeeded()) {
612 GrPrintf("Failed to get space for vertices!\n");
613 return;
614 }
615
616 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
617
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000618 GrEffectRef* effect = GrAlignedRectEffect::Create();
619 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000620 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000621
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000622 SkRect devRect;
623 combinedMatrix.mapRect(&devRect, rect);
624
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000625 SkRect devBounds = {
626 devRect.fLeft - SK_ScalarHalf,
627 devRect.fTop - SK_ScalarHalf,
628 devRect.fRight + SK_ScalarHalf,
629 devRect.fBottom + SK_ScalarHalf
630 };
631
632 GrPoint widthHeight = {
633 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
634 SkScalarHalf(devRect.height()) + SK_ScalarHalf
635 };
636
637 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
638 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
639 verts[0].fWidthHeight = widthHeight;
640
641 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
642 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
643 verts[1].fWidthHeight = widthHeight;
644
645 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
646 verts[2].fOffset = widthHeight;
647 verts[2].fWidthHeight = widthHeight;
648
649 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
650 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
651 verts[3].fWidthHeight = widthHeight;
652
653 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
654 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
655 target->resetIndexSource();
656}
657
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000658void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000659 GrDrawTarget* target,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000660 const SkRect& rect,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000661 const SkMatrix& combinedMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000662 const SkRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000663 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000664 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000665 GrVec devStrokeSize;
666 if (width > 0) {
667 devStrokeSize.set(width, width);
668 combinedMatrix.mapVectors(&devStrokeSize, 1);
669 devStrokeSize.setAbs(devStrokeSize);
670 } else {
671 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
672 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000673
robertphillips@google.com18136d12013-05-10 11:05:58 +0000674 const SkScalar dx = devStrokeSize.fX;
675 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000676 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
677 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000678
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000679 // Temporarily #if'ed out. We don't want to pass in the devRect but
680 // right now it is computed in GrContext::apply_aa_to_rect and we don't
681 // want to throw away the work
682#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000683 SkRect devRect;
684 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000685#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000686
bsalomon@google.com81712882012-11-01 17:12:34 +0000687 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000688 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000689 SkScalar w = devRect.width() - dx;
690 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000691 spare = GrMin(w, h);
692 }
693
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000694 SkRect devOutside(devRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000695 devOutside.outset(rx, ry);
696
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000697 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000698 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000699 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000700 return;
701 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000702
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000703 SkRect devInside(devRect);
704 devInside.inset(rx, ry);
705
706 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
707}
708
709void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
710 GrDrawTarget* target,
711 const SkRect& devOutside,
712 const SkRect& devInside,
713 bool useVertexCoverage) {
714 GrDrawState* drawState = target->drawState();
715
robertphillips@google.com42903302013-04-20 12:26:07 +0000716 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000717
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000718 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000719 if (!geo.succeeded()) {
720 GrPrintf("Failed to get space for vertices!\n");
721 return;
722 }
723 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
724 if (NULL == indexBuffer) {
725 GrPrintf("Failed to create index buffer!\n");
726 return;
727 }
728
729 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000730 size_t vsize = drawState->getVertexSize();
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000731 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000732
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000733 // We create vertices for four nested rectangles. There are two ramps from 0 to full
734 // coverage, one on the exterior of the stroke and the other on the interior.
735 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000736 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
737 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
738 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
739 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
740
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000741#ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
robertphillips@google.com353f0972013-06-28 17:57:06 +0000742 // TODO: this only really works if the X & Y margins are the same all around
743 // the rect
744 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
745 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
746 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
747 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
748 SkASSERT(inset >= 0);
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000749#else
750 SkScalar inset = SK_ScalarHalf;
751#endif
robertphillips@google.com353f0972013-06-28 17:57:06 +0000752
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000753 // outermost
754 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com353f0972013-06-28 17:57:06 +0000755 // inner two
756 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
757 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000758 // innermost
759 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000760
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000761 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000762 verts += sizeof(GrPoint);
763 for (int i = 0; i < 4; ++i) {
764 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
765 }
766
robertphillips@google.com353f0972013-06-28 17:57:06 +0000767 int scale;
768 if (inset < SK_ScalarHalf) {
769 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
770 SkASSERT(scale >= 0 && scale <= 255);
771 } else {
772 scale = 0xff;
773 }
774
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000775 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000776 GrColor innerColor;
777 if (useVertexCoverage) {
robertphillips@google.com353f0972013-06-28 17:57:06 +0000778 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000779 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000780 if (0xff == scale) {
skia.committer@gmail.com0d55dd72013-07-02 07:00:59 +0000781 innerColor = target->getDrawState().getColor();
782 } else {
robertphillips@google.comc111ce22013-07-01 13:10:10 +0000783 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
784 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000785 }
robertphillips@google.com353f0972013-06-28 17:57:06 +0000786
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000787 verts += 4 * vsize;
788 for (int i = 0; i < 8; ++i) {
789 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
790 }
791
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000792 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000793 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000794 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000795 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
796 }
797
798 target->setIndexSourceToBuffer(indexBuffer);
799 target->drawIndexed(kTriangles_GrPrimitiveType,
800 0, 0, 16, aaStrokeRectIndexCount());
801}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000802
803void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
804 GrDrawTarget* target,
805 const SkRect rects[2],
806 const SkMatrix& combinedMatrix,
807 bool useVertexCoverage) {
808 SkASSERT(combinedMatrix.rectStaysRect());
809 SkASSERT(!rects[1].isEmpty());
810
811 SkRect devOutside, devInside;
812 combinedMatrix.mapRect(&devOutside, rects[0]);
813 // can't call mapRect for devInside since it calls sort
814 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
815
816 if (devInside.isEmpty()) {
817 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
818 return;
819 }
820
821 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
822}