blob: eacd3f1ec9ab7c8d8196be93adddc567ecac86e1 [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() {
33 static SkAutoTUnref<GrEffectRef> gRectEffectRef(
34 CreateEffectRef(AutoEffectUnref(SkNEW(GrRectEffect))));
35 gRectEffectRef.get()->ref();
36 return gRectEffectRef;
37 }
38
39 virtual ~GrRectEffect() {}
40
41 static const char* Name() { return "RectEdge"; }
42
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000043 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000044 uint32_t* validFlags) const SK_OVERRIDE {
45 *validFlags = 0;
46 }
47
48 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
49 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
50 }
51
52 class GLEffect : public GrGLEffect {
53 public:
54 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
55 : INHERITED (factory) {}
56
57 virtual void emitCode(GrGLShaderBuilder* builder,
58 const GrDrawEffect& drawEffect,
59 EffectKey key,
60 const char* outputColor,
61 const char* inputColor,
62 const TextureSamplerArray& samplers) SK_OVERRIDE {
63 // setup the varying for the center point and the unit vector
64 // that points down the height of the rect
65 const char *vsRectEdgeName, *fsRectEdgeName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000066 builder->addVarying(kVec4f_GrSLType, "RectEdge",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000067 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000068 const SkString* attr0Name =
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000069 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
70 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
71
72 // setup the varying for width/2+.5 and height/2+.5
73 const char *vsWidthHeightName, *fsWidthHeightName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000074 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000075 &vsWidthHeightName, &fsWidthHeightName);
76 const SkString* attr1Name =
77 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
78 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
79
80 // TODO: compute these scale factors in the VS
81 // These scale factors adjust the coverage for < 1 pixel wide/high rects
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000082 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000083 fsWidthHeightName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000084 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000085 fsWidthHeightName);
86
87 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +000088 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +000089 builder->fragmentPosition(), fsRectEdgeName);
90 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
91 fsRectEdgeName, fsRectEdgeName);
92 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n",
93 fsWidthHeightName);
94
95 // Compute the coverage for the rect's height and merge with the width
96 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
97 fsRectEdgeName);
98 builder->fsCodeAppendf(
99 "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n",
100 fsWidthHeightName);
101
102 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000103 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000104 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
105 }
106
107 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
108 return 0;
109 }
110
111 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
112
113 private:
114 typedef GrGLEffect INHERITED;
115 };
116
117
118private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000119 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000120 this->addVertexAttrib(kVec4f_GrSLType);
121 this->addVertexAttrib(kVec2f_GrSLType);
122 }
123
124 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
125
126 GR_DECLARE_EFFECT_TEST;
127
128 typedef GrEffect INHERITED;
129};
130
131
132GR_DEFINE_EFFECT_TEST(GrRectEffect);
133
134GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
135 GrContext* context,
136 const GrDrawTargetCaps&,
137 GrTexture* textures[]) {
138 return GrRectEffect::Create();
139}
140
141///////////////////////////////////////////////////////////////////////////////
142
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000143namespace {
144
robertphillips@google.com42903302013-04-20 12:26:07 +0000145extern const GrVertexAttrib gAARectCoverageAttribs[] = {
146 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
147 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
148};
149
150extern const GrVertexAttrib gAARectColorAttribs[] = {
151 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
152 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
153};
154
155static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
156 if (useCoverage) {
157 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
158 } else {
159 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
160 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000161}
162
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000163static void set_inset_fan(GrPoint* pts, size_t stride,
164 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000165 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
166 r.fRight - dx, r.fBottom - dy, stride);
167}
168
169};
170
171void GrAARectRenderer::reset() {
172 GrSafeSetNull(fAAFillRectIndexBuffer);
173 GrSafeSetNull(fAAStrokeRectIndexBuffer);
174}
175
robertphillips@google.com6d067302012-12-18 21:47:47 +0000176static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000177 0, 1, 5, 5, 4, 0,
178 1, 2, 6, 6, 5, 1,
179 2, 3, 7, 7, 6, 2,
180 3, 0, 4, 4, 7, 3,
181 4, 5, 6, 6, 7, 4,
182};
183
robertphillips@google.com6d067302012-12-18 21:47:47 +0000184static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
185static const int kVertsPerAAFillRect = 8;
186static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000187
188GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000189 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
190 sizeof(uint16_t) *
191 kNumAAFillRectsInIndexBuffer;
192
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000193 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000194 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000195 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000196 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
197 bool useTempData = (NULL == data);
198 if (useTempData) {
199 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
200 }
201 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
202 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
203 // the inner rect (for AA) and 2 for the inner rect.
204 int baseIdx = i * kIndicesPerAAFillRect;
205 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
206 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
207 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
208 }
209 }
210 if (useTempData) {
211 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
212 GrCrash("Can't get AA Fill Rect indices into buffer!");
213 }
214 SkDELETE_ARRAY(data);
215 } else {
216 fAAFillRectIndexBuffer->unlock();
217 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000218 }
219 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000220
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000221 return fAAFillRectIndexBuffer;
222}
223
robertphillips@google.com6d067302012-12-18 21:47:47 +0000224static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000225 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
226 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
227 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
228 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
229
230 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
231 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
232 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
233 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
234
235 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
236 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
237 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
238 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
239};
240
241int GrAARectRenderer::aaStrokeRectIndexCount() {
242 return GR_ARRAY_COUNT(gStrokeAARectIdx);
243}
244
245GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
246 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000247 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000248 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
249 if (NULL != fAAStrokeRectIndexBuffer) {
250#if GR_DEBUG
251 bool updated =
252#endif
253 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
254 sizeof(gStrokeAARectIdx));
255 GR_DEBUGASSERT(updated);
256 }
257 }
258 return fAAStrokeRectIndexBuffer;
259}
260
261void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000262 GrDrawTarget* target,
263 const GrRect& devRect,
264 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000265 GrDrawState* drawState = target->drawState();
266
robertphillips@google.com42903302013-04-20 12:26:07 +0000267 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000269 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000270 if (!geo.succeeded()) {
271 GrPrintf("Failed to get space for vertices!\n");
272 return;
273 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000274
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000275 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
276 if (NULL == indexBuffer) {
277 GrPrintf("Failed to create index buffer!\n");
278 return;
279 }
280
281 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000282 size_t vsize = drawState->getVertexSize();
283 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000284
285 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
286 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
287
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000288 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
289 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290
291 verts += sizeof(GrPoint);
292 for (int i = 0; i < 4; ++i) {
293 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
294 }
295
296 GrColor innerColor;
297 if (useVertexCoverage) {
298 innerColor = 0xffffffff;
299 } else {
300 innerColor = target->getDrawState().getColor();
301 }
302
303 verts += 4 * vsize;
304 for (int i = 0; i < 4; ++i) {
305 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
306 }
307
308 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000309 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
310 kVertsPerAAFillRect,
311 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000312 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000313}
314
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000315struct RectVertex {
316 GrPoint fPos;
317 GrPoint fCenter;
318 GrPoint fDir;
319 GrPoint fWidthHeight;
320};
321
robertphillips@google.com42903302013-04-20 12:26:07 +0000322namespace {
323
324extern const GrVertexAttrib gAARectVertexAttribs[] = {
325 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
326 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
327 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
328};
329
330};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000331
332void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
333 GrDrawTarget* target,
334 const GrRect& rect,
335 const SkMatrix& combinedMatrix,
336 const GrRect& devRect,
337 bool useVertexCoverage) {
338 GrDrawState* drawState = target->drawState();
339
340 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
341 combinedMatrix.mapPoints(&center, 1);
342
343 // compute transformed (0, 1) vector
344 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
345 dir.normalize();
346
347 // compute transformed (width, 0) and (0, height) vectors
348 SkVector vec[2] = {
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000349 { combinedMatrix[SkMatrix::kMScaleX] * rect.width(),
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000350 combinedMatrix[SkMatrix::kMSkewY] * rect.width() },
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000351 { combinedMatrix[SkMatrix::kMSkewX] * rect.height(),
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000352 combinedMatrix[SkMatrix::kMScaleY] * rect.height() }
353 };
354
355 SkScalar newWidth = vec[0].length() / 2.0f + 0.5f;
356 SkScalar newHeight = vec[1].length() / 2.0f + 0.5f;
357
robertphillips@google.com42903302013-04-20 12:26:07 +0000358 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000359 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
360
361 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
362 if (!geo.succeeded()) {
363 GrPrintf("Failed to get space for vertices!\n");
364 return;
365 }
366
367 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
368
369 enum {
370 // the edge effects share this stage with glyph rendering
371 // (kGlyphMaskStage in GrTextContext) && SW path rendering
372 // (kPathMaskStage in GrSWMaskHelper)
373 kEdgeEffectStage = GrPaint::kTotalStages,
374 };
375
376 GrEffectRef* effect = GrRectEffect::Create();
377 static const int kRectAttrIndex = 1;
378 static const int kWidthIndex = 2;
379 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
380
381 for (int i = 0; i < 4; ++i) {
382 verts[i].fCenter = center;
383 verts[i].fDir = dir;
384 verts[i].fWidthHeight.fX = newWidth;
385 verts[i].fWidthHeight.fY = newHeight;
386 }
387
388 SkRect devBounds = {
389 devRect.fLeft - SK_ScalarHalf,
390 devRect.fTop - SK_ScalarHalf,
391 devRect.fRight + SK_ScalarHalf,
392 devRect.fBottom + SK_ScalarHalf
393 };
394
395 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
396 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
397 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
398 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
399
400 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
401 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
402 target->resetIndexSource();
403}
404
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000405void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000406 GrDrawTarget* target,
407 const GrRect& devRect,
408 const GrVec& devStrokeSize,
409 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000410 GrDrawState* drawState = target->drawState();
411
bsalomon@google.com81712882012-11-01 17:12:34 +0000412 const SkScalar& dx = devStrokeSize.fX;
413 const SkScalar& dy = devStrokeSize.fY;
414 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
415 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000416
bsalomon@google.com81712882012-11-01 17:12:34 +0000417 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000418 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000419 SkScalar w = devRect.width() - dx;
420 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000421 spare = GrMin(w, h);
422 }
423
424 if (spare <= 0) {
425 GrRect r(devRect);
426 r.inset(-rx, -ry);
427 this->fillAARect(gpu, target, r, useVertexCoverage);
428 return;
429 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000430
robertphillips@google.com42903302013-04-20 12:26:07 +0000431 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000432
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000433 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434 if (!geo.succeeded()) {
435 GrPrintf("Failed to get space for vertices!\n");
436 return;
437 }
438 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
439 if (NULL == indexBuffer) {
440 GrPrintf("Failed to create index buffer!\n");
441 return;
442 }
443
444 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000445 size_t vsize = drawState->getVertexSize();
446 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000447
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000448 // We create vertices for four nested rectangles. There are two ramps from 0 to full
449 // coverage, one on the exterior of the stroke and the other on the interior.
450 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000451 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
452 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
453 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
454 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
455
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000456 set_inset_fan(fan0Pos, vsize, devRect,
457 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
458 set_inset_fan(fan1Pos, vsize, devRect,
459 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
460 set_inset_fan(fan2Pos, vsize, devRect,
461 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
462 set_inset_fan(fan3Pos, vsize, devRect,
463 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000464
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000465 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000466 verts += sizeof(GrPoint);
467 for (int i = 0; i < 4; ++i) {
468 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
469 }
470
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000471 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000472 GrColor innerColor;
473 if (useVertexCoverage) {
474 innerColor = 0xffffffff;
475 } else {
476 innerColor = target->getDrawState().getColor();
477 }
478 verts += 4 * vsize;
479 for (int i = 0; i < 8; ++i) {
480 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
481 }
482
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000483 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000484 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000485 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000486 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
487 }
488
489 target->setIndexSourceToBuffer(indexBuffer);
490 target->drawIndexed(kTriangles_GrPrimitiveType,
491 0, 0, 16, aaStrokeRectIndexCount());
492}