blob: 418d80d713859e6f0aabf2ae5531fc291cc7d73f [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.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.comdf3695e2013-04-09 14:01:44 +000016class GrGLRectEffect;
17
18/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000019 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000020 * for an arbitrarily oriented rect. The rect is specified as:
21 * Center of the rect
22 * Unit vector point down the height of the rect
23 * Half width + 0.5
24 * Half height + 0.5
25 * The center and vector are stored in a vec4 varying ("RectEdge") with the
26 * center in the xy components and the vector in the zw components.
27 * The munged width and height are stored in a vec2 varying ("WidthHeight")
28 * with the width in x and the height in y.
29 */
30class GrRectEffect : public GrEffect {
31public:
32 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +000033 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
34 gRectEffect->ref();
35 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000036 }
37
38 virtual ~GrRectEffect() {}
39
40 static const char* Name() { return "RectEdge"; }
41
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000042 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000043 uint32_t* validFlags) const SK_OVERRIDE {
44 *validFlags = 0;
45 }
46
47 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
48 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
49 }
50
51 class GLEffect : public GrGLEffect {
52 public:
53 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
54 : INHERITED (factory) {}
55
56 virtual void emitCode(GrGLShaderBuilder* builder,
57 const GrDrawEffect& drawEffect,
58 EffectKey key,
59 const char* outputColor,
60 const char* inputColor,
61 const TextureSamplerArray& samplers) SK_OVERRIDE {
62 // setup the varying for the center point and the unit vector
63 // that points down the height of the rect
64 const char *vsRectEdgeName, *fsRectEdgeName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000065 builder->addVarying(kVec4f_GrSLType, "RectEdge",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000066 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000067 const SkString* attr0Name =
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000068 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
69 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
70
71 // setup the varying for width/2+.5 and height/2+.5
72 const char *vsWidthHeightName, *fsWidthHeightName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000073 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000074 &vsWidthHeightName, &fsWidthHeightName);
75 const SkString* attr1Name =
76 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
77 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
78
79 // TODO: compute these scale factors in the VS
80 // These scale factors adjust the coverage for < 1 pixel wide/high rects
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000081 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000082 fsWidthHeightName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000083 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000084 fsWidthHeightName);
85
86 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000087 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000088 builder->fragmentPosition(), fsRectEdgeName);
89 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
90 fsRectEdgeName, fsRectEdgeName);
91 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n",
92 fsWidthHeightName);
93
94 // Compute the coverage for the rect's height and merge with the width
95 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
96 fsRectEdgeName);
97 builder->fsCodeAppendf(
98 "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n",
99 fsWidthHeightName);
100
101 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000102 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000103 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
104 }
105
106 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
107 return 0;
108 }
109
110 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
111
112 private:
113 typedef GrGLEffect INHERITED;
114 };
115
116
117private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000118 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000119 this->addVertexAttrib(kVec4f_GrSLType);
120 this->addVertexAttrib(kVec2f_GrSLType);
121 }
122
123 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
124
125 GR_DECLARE_EFFECT_TEST;
126
127 typedef GrEffect INHERITED;
128};
129
130
131GR_DEFINE_EFFECT_TEST(GrRectEffect);
132
133GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
134 GrContext* context,
135 const GrDrawTargetCaps&,
136 GrTexture* textures[]) {
137 return GrRectEffect::Create();
138}
139
140///////////////////////////////////////////////////////////////////////////////
141
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000142namespace {
143
robertphillips@google.com42903302013-04-20 12:26:07 +0000144extern const GrVertexAttrib gAARectCoverageAttribs[] = {
145 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
146 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
147};
148
149extern const GrVertexAttrib gAARectColorAttribs[] = {
150 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
151 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
152};
153
154static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
155 if (useCoverage) {
156 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
157 } else {
158 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
159 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000160}
161
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000162static void set_inset_fan(GrPoint* pts, size_t stride,
163 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000164 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
165 r.fRight - dx, r.fBottom - dy, stride);
166}
167
168};
169
170void GrAARectRenderer::reset() {
171 GrSafeSetNull(fAAFillRectIndexBuffer);
172 GrSafeSetNull(fAAStrokeRectIndexBuffer);
173}
174
robertphillips@google.com6d067302012-12-18 21:47:47 +0000175static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000176 0, 1, 5, 5, 4, 0,
177 1, 2, 6, 6, 5, 1,
178 2, 3, 7, 7, 6, 2,
179 3, 0, 4, 4, 7, 3,
180 4, 5, 6, 6, 7, 4,
181};
182
robertphillips@google.com6d067302012-12-18 21:47:47 +0000183static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
184static const int kVertsPerAAFillRect = 8;
185static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000186
187GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000188 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
189 sizeof(uint16_t) *
190 kNumAAFillRectsInIndexBuffer;
191
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000192 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000193 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000194 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000195 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
196 bool useTempData = (NULL == data);
197 if (useTempData) {
198 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
199 }
200 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
201 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
202 // the inner rect (for AA) and 2 for the inner rect.
203 int baseIdx = i * kIndicesPerAAFillRect;
204 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
205 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
206 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
207 }
208 }
209 if (useTempData) {
210 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
211 GrCrash("Can't get AA Fill Rect indices into buffer!");
212 }
213 SkDELETE_ARRAY(data);
214 } else {
215 fAAFillRectIndexBuffer->unlock();
216 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000217 }
218 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000219
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000220 return fAAFillRectIndexBuffer;
221}
222
robertphillips@google.com6d067302012-12-18 21:47:47 +0000223static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000224 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
225 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
226 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
227 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
228
229 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
230 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
231 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
232 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
233
234 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
235 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
236 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
237 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
238};
239
240int GrAARectRenderer::aaStrokeRectIndexCount() {
241 return GR_ARRAY_COUNT(gStrokeAARectIdx);
242}
243
244GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
245 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000246 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000247 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
248 if (NULL != fAAStrokeRectIndexBuffer) {
249#if GR_DEBUG
250 bool updated =
251#endif
252 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
253 sizeof(gStrokeAARectIdx));
254 GR_DEBUGASSERT(updated);
255 }
256 }
257 return fAAStrokeRectIndexBuffer;
258}
259
260void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000261 GrDrawTarget* target,
262 const GrRect& devRect,
263 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000264 GrDrawState* drawState = target->drawState();
265
robertphillips@google.com42903302013-04-20 12:26:07 +0000266 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000268 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000269 if (!geo.succeeded()) {
270 GrPrintf("Failed to get space for vertices!\n");
271 return;
272 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000273
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000274 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
275 if (NULL == indexBuffer) {
276 GrPrintf("Failed to create index buffer!\n");
277 return;
278 }
279
280 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000281 size_t vsize = drawState->getVertexSize();
282 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000283
284 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
285 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
286
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000287 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
288 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000289
290 verts += sizeof(GrPoint);
291 for (int i = 0; i < 4; ++i) {
292 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
293 }
294
295 GrColor innerColor;
296 if (useVertexCoverage) {
297 innerColor = 0xffffffff;
298 } else {
299 innerColor = target->getDrawState().getColor();
300 }
301
302 verts += 4 * vsize;
303 for (int i = 0; i < 4; ++i) {
304 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
305 }
306
307 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000308 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
309 kVertsPerAAFillRect,
310 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000311 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000312}
313
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000314struct RectVertex {
315 GrPoint fPos;
316 GrPoint fCenter;
317 GrPoint fDir;
318 GrPoint fWidthHeight;
319};
320
robertphillips@google.com42903302013-04-20 12:26:07 +0000321namespace {
322
323extern const GrVertexAttrib gAARectVertexAttribs[] = {
324 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
325 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
326 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
327};
328
329};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000330
331void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
332 GrDrawTarget* target,
333 const GrRect& rect,
334 const SkMatrix& combinedMatrix,
335 const GrRect& devRect,
336 bool useVertexCoverage) {
337 GrDrawState* drawState = target->drawState();
338
339 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
340 combinedMatrix.mapPoints(&center, 1);
341
342 // compute transformed (0, 1) vector
343 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
344 dir.normalize();
345
346 // compute transformed (width, 0) and (0, height) vectors
347 SkVector vec[2] = {
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000348 { combinedMatrix[SkMatrix::kMScaleX] * rect.width(),
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000349 combinedMatrix[SkMatrix::kMSkewY] * rect.width() },
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000350 { combinedMatrix[SkMatrix::kMSkewX] * rect.height(),
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000351 combinedMatrix[SkMatrix::kMScaleY] * rect.height() }
352 };
353
354 SkScalar newWidth = vec[0].length() / 2.0f + 0.5f;
355 SkScalar newHeight = vec[1].length() / 2.0f + 0.5f;
356
robertphillips@google.com42903302013-04-20 12:26:07 +0000357 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000358 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
359
360 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
361 if (!geo.succeeded()) {
362 GrPrintf("Failed to get space for vertices!\n");
363 return;
364 }
365
366 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
367
368 enum {
369 // the edge effects share this stage with glyph rendering
370 // (kGlyphMaskStage in GrTextContext) && SW path rendering
371 // (kPathMaskStage in GrSWMaskHelper)
372 kEdgeEffectStage = GrPaint::kTotalStages,
373 };
374
375 GrEffectRef* effect = GrRectEffect::Create();
376 static const int kRectAttrIndex = 1;
377 static const int kWidthIndex = 2;
378 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
379
380 for (int i = 0; i < 4; ++i) {
381 verts[i].fCenter = center;
382 verts[i].fDir = dir;
383 verts[i].fWidthHeight.fX = newWidth;
384 verts[i].fWidthHeight.fY = newHeight;
385 }
386
387 SkRect devBounds = {
388 devRect.fLeft - SK_ScalarHalf,
389 devRect.fTop - SK_ScalarHalf,
390 devRect.fRight + SK_ScalarHalf,
391 devRect.fBottom + SK_ScalarHalf
392 };
393
394 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
395 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
396 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
397 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
398
399 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
400 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
401 target->resetIndexSource();
402}
403
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000404void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000405 GrDrawTarget* target,
406 const GrRect& devRect,
407 const GrVec& devStrokeSize,
408 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000409 GrDrawState* drawState = target->drawState();
410
bsalomon@google.com81712882012-11-01 17:12:34 +0000411 const SkScalar& dx = devStrokeSize.fX;
412 const SkScalar& dy = devStrokeSize.fY;
413 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
414 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000415
bsalomon@google.com81712882012-11-01 17:12:34 +0000416 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000417 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000418 SkScalar w = devRect.width() - dx;
419 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000420 spare = GrMin(w, h);
421 }
422
423 if (spare <= 0) {
424 GrRect r(devRect);
425 r.inset(-rx, -ry);
426 this->fillAARect(gpu, target, r, useVertexCoverage);
427 return;
428 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000429
robertphillips@google.com42903302013-04-20 12:26:07 +0000430 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000431
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000432 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000433 if (!geo.succeeded()) {
434 GrPrintf("Failed to get space for vertices!\n");
435 return;
436 }
437 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
438 if (NULL == indexBuffer) {
439 GrPrintf("Failed to create index buffer!\n");
440 return;
441 }
442
443 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000444 size_t vsize = drawState->getVertexSize();
445 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000446
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000447 // We create vertices for four nested rectangles. There are two ramps from 0 to full
448 // coverage, one on the exterior of the stroke and the other on the interior.
449 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000450 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
451 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
452 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
453 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
454
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000455 set_inset_fan(fan0Pos, vsize, devRect,
456 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
457 set_inset_fan(fan1Pos, vsize, devRect,
458 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
459 set_inset_fan(fan2Pos, vsize, devRect,
460 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
461 set_inset_fan(fan3Pos, vsize, devRect,
462 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000464 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000465 verts += sizeof(GrPoint);
466 for (int i = 0; i < 4; ++i) {
467 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
468 }
469
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000470 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000471 GrColor innerColor;
472 if (useVertexCoverage) {
473 innerColor = 0xffffffff;
474 } else {
475 innerColor = target->getDrawState().getColor();
476 }
477 verts += 4 * vsize;
478 for (int i = 0; i < 8; ++i) {
479 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
480 }
481
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000482 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000483 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000484 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000485 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
486 }
487
488 target->setIndexSourceToBuffer(indexBuffer);
489 target->drawIndexed(kTriangles_GrPrimitiveType,
490 0, 0, 16, aaStrokeRectIndexCount());
491}