blob: df4e32adc127a1319ed60c06cfda269a21f83bcc [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
47 virtual void emitCode(GrGLShaderBuilder* builder,
48 const GrDrawEffect& drawEffect,
49 EffectKey key,
50 const char* outputColor,
51 const char* inputColor,
52 const TextureSamplerArray& samplers) SK_OVERRIDE {
53 // setup the varying for the Axis aligned rect effect
54 // xy -> interpolated offset
55 // zw -> w/2+0.5, h/2+0.5
56 const char *vsRectName, *fsRectName;
57 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
58 const SkString* attr0Name =
59 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
60 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
61
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000062 // TODO: compute all these offsets, spans, and scales in the VS
63 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
64 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
65 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
66 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
67 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
68 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
69 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
70 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
71 // value of coverage that is used. In other words it is the coverage that is
72 // used in the interior of the rect after the ramp.
robertphillips@google.com07a05242013-06-14 17:45:30 +000073 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
74 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000075
76 // Compute the coverage for the rect's width
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000077 builder->fsCodeAppendf(
commit-bot@chromium.org99e0d082013-06-14 14:58:50 +000078 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
79 fsRectName);
80 // Compute the coverage for the rect's height and merge with the width
81 builder->fsCodeAppendf(
82 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
83 fsRectName, fsRectName);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +000084
85 SkString modulate;
86 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
87 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
88 }
89
90 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
91 return 0;
92 }
93
94 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
95
96 private:
97 typedef GrGLEffect INHERITED;
98 };
99
100
101private:
102 GrAlignedRectEffect() : GrEffect() {
103 this->addVertexAttrib(kVec4f_GrSLType);
104 }
105
106 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
107
108 GR_DECLARE_EFFECT_TEST;
109
110 typedef GrEffect INHERITED;
111};
112
113
114GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
115
116GrEffectRef* GrAlignedRectEffect::TestCreate(SkMWCRandom* random,
117 GrContext* context,
118 const GrDrawTargetCaps&,
119 GrTexture* textures[]) {
120 return GrAlignedRectEffect::Create();
121}
122
123///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000124class GrGLRectEffect;
125
126/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000127 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000128 * for an arbitrarily oriented rect. The rect is specified as:
129 * Center of the rect
130 * Unit vector point down the height of the rect
131 * Half width + 0.5
132 * Half height + 0.5
133 * The center and vector are stored in a vec4 varying ("RectEdge") with the
134 * center in the xy components and the vector in the zw components.
135 * The munged width and height are stored in a vec2 varying ("WidthHeight")
136 * with the width in x and the height in y.
137 */
138class GrRectEffect : public GrEffect {
139public:
140 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000141 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
142 gRectEffect->ref();
143 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000144 }
145
146 virtual ~GrRectEffect() {}
147
148 static const char* Name() { return "RectEdge"; }
149
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000150 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000151 uint32_t* validFlags) const SK_OVERRIDE {
152 *validFlags = 0;
153 }
154
155 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
156 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
157 }
158
159 class GLEffect : public GrGLEffect {
160 public:
161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
162 : INHERITED (factory) {}
163
164 virtual void emitCode(GrGLShaderBuilder* builder,
165 const GrDrawEffect& drawEffect,
166 EffectKey key,
167 const char* outputColor,
168 const char* inputColor,
169 const TextureSamplerArray& samplers) SK_OVERRIDE {
170 // setup the varying for the center point and the unit vector
171 // that points down the height of the rect
172 const char *vsRectEdgeName, *fsRectEdgeName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000173 builder->addVarying(kVec4f_GrSLType, "RectEdge",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000174 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000175 const SkString* attr0Name =
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000176 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
177 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
178
179 // setup the varying for width/2+.5 and height/2+.5
180 const char *vsWidthHeightName, *fsWidthHeightName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000181 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000182 &vsWidthHeightName, &fsWidthHeightName);
183 const SkString* attr1Name =
184 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
185 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
186
187 // TODO: compute these scale factors in the VS
188 // These scale factors adjust the coverage for < 1 pixel wide/high rects
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000189 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000190 fsWidthHeightName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000191 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000192 fsWidthHeightName);
193
194 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000195 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000196 builder->fragmentPosition(), fsRectEdgeName);
197 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
198 fsRectEdgeName, fsRectEdgeName);
199 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n",
200 fsWidthHeightName);
201
202 // Compute the coverage for the rect's height and merge with the width
203 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
204 fsRectEdgeName);
205 builder->fsCodeAppendf(
206 "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n",
207 fsWidthHeightName);
208
209 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000210 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000211 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
212 }
213
214 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
215 return 0;
216 }
217
218 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
219
220 private:
221 typedef GrGLEffect INHERITED;
222 };
223
224
225private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000226 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000227 this->addVertexAttrib(kVec4f_GrSLType);
228 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000229 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000230 }
231
232 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
233
234 GR_DECLARE_EFFECT_TEST;
235
236 typedef GrEffect INHERITED;
237};
238
239
240GR_DEFINE_EFFECT_TEST(GrRectEffect);
241
242GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
243 GrContext* context,
244 const GrDrawTargetCaps&,
245 GrTexture* textures[]) {
246 return GrRectEffect::Create();
247}
248
249///////////////////////////////////////////////////////////////////////////////
250
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000251namespace {
252
robertphillips@google.com42903302013-04-20 12:26:07 +0000253extern const GrVertexAttrib gAARectCoverageAttribs[] = {
254 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
255 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
256};
257
258extern const GrVertexAttrib gAARectColorAttribs[] = {
259 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
260 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
261};
262
263static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
264 if (useCoverage) {
265 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
266 } else {
267 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
268 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000269}
270
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000271static void set_inset_fan(GrPoint* pts, size_t stride,
272 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000273 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
274 r.fRight - dx, r.fBottom - dy, stride);
275}
276
277};
278
279void GrAARectRenderer::reset() {
280 GrSafeSetNull(fAAFillRectIndexBuffer);
281 GrSafeSetNull(fAAStrokeRectIndexBuffer);
282}
283
robertphillips@google.com6d067302012-12-18 21:47:47 +0000284static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000285 0, 1, 5, 5, 4, 0,
286 1, 2, 6, 6, 5, 1,
287 2, 3, 7, 7, 6, 2,
288 3, 0, 4, 4, 7, 3,
289 4, 5, 6, 6, 7, 4,
290};
291
robertphillips@google.com6d067302012-12-18 21:47:47 +0000292static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
293static const int kVertsPerAAFillRect = 8;
294static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000295
296GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000297 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
298 sizeof(uint16_t) *
299 kNumAAFillRectsInIndexBuffer;
300
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000301 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000302 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000303 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000304 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
305 bool useTempData = (NULL == data);
306 if (useTempData) {
307 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
308 }
309 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
310 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
311 // the inner rect (for AA) and 2 for the inner rect.
312 int baseIdx = i * kIndicesPerAAFillRect;
313 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
314 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
315 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
316 }
317 }
318 if (useTempData) {
319 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
320 GrCrash("Can't get AA Fill Rect indices into buffer!");
321 }
322 SkDELETE_ARRAY(data);
323 } else {
324 fAAFillRectIndexBuffer->unlock();
325 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000326 }
327 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000328
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000329 return fAAFillRectIndexBuffer;
330}
331
robertphillips@google.com6d067302012-12-18 21:47:47 +0000332static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000333 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
334 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
335 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
336 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
337
338 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
339 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
340 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
341 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
342
343 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
344 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
345 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
346 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
347};
348
349int GrAARectRenderer::aaStrokeRectIndexCount() {
350 return GR_ARRAY_COUNT(gStrokeAARectIdx);
351}
352
353GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
354 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000355 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000356 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
357 if (NULL != fAAStrokeRectIndexBuffer) {
358#if GR_DEBUG
359 bool updated =
360#endif
361 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
362 sizeof(gStrokeAARectIdx));
363 GR_DEBUGASSERT(updated);
364 }
365 }
366 return fAAStrokeRectIndexBuffer;
367}
368
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000369void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
370 GrDrawTarget* target,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000371 const GrRect& rect,
372 const SkMatrix& combinedMatrix,
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000373 const GrRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000374 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000375 GrDrawState* drawState = target->drawState();
376
robertphillips@google.com42903302013-04-20 12:26:07 +0000377 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000378
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000379 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000380 if (!geo.succeeded()) {
381 GrPrintf("Failed to get space for vertices!\n");
382 return;
383 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000384
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000385 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
386 if (NULL == indexBuffer) {
387 GrPrintf("Failed to create index buffer!\n");
388 return;
389 }
390
391 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000392 size_t vsize = drawState->getVertexSize();
393 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000394
395 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
396 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
397
robertphillips@google.com908aed82013-05-28 13:16:20 +0000398 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
399 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
400
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000401 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000402 // Temporarily #if'ed out. We don't want to pass in the devRect but
403 // right now it is computed in GrContext::apply_aa_to_rect and we don't
404 // want to throw away the work
405#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000406 SkRect devRect;
407 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000408#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000409
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000410 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000411 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000412 } else {
413 // compute transformed (1, 0) and (0, 1) vectors
414 SkVector vec[2] = {
415 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
416 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
417 };
418
419 vec[0].normalize();
420 vec[0].scale(SK_ScalarHalf);
421 vec[1].normalize();
422 vec[1].scale(SK_ScalarHalf);
423
robertphillips@google.com91b71162013-05-10 14:09:54 +0000424 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000425 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
426 rect.fRight, rect.fBottom, vsize);
427 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
428
robertphillips@google.com91b71162013-05-10 14:09:54 +0000429 // Now create the inset points and then outset the original
430 // rotated points
431
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000432 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000433 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000434 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
435 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
436 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000437 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000438 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
439 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
440 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000441 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000442 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
443 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
444 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000445 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000446 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
447 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
448 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000449
450 verts += sizeof(GrPoint);
451 for (int i = 0; i < 4; ++i) {
452 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
453 }
454
robertphillips@google.com908aed82013-05-28 13:16:20 +0000455 int scale;
456 if (inset < SK_ScalarHalf) {
457 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
458 SkASSERT(scale >= 0 && scale <= 255);
459 } else {
460 scale = 0xff;
461 }
462
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000464 if (useVertexCoverage) {
robertphillips@google.com908aed82013-05-28 13:16:20 +0000465 innerColor = scale | (scale << 8) | (scale << 16) | (scale << 24);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000466 } else {
robertphillips@google.com908aed82013-05-28 13:16:20 +0000467 if (0xff == scale) {
468 innerColor = target->getDrawState().getColor();
469 } else {
470 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
471 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000472 }
473
474 verts += 4 * vsize;
475 for (int i = 0; i < 4; ++i) {
476 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
477 }
478
479 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000480 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
481 kVertsPerAAFillRect,
482 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000483 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000484}
485
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000486namespace {
487
488// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000489struct RectVertex {
490 GrPoint fPos;
491 GrPoint fCenter;
492 GrPoint fDir;
493 GrPoint fWidthHeight;
494};
495
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000496// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000497extern const GrVertexAttrib gAARectVertexAttribs[] = {
498 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
499 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
500 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
501};
502
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000503// Axis Aligned
504struct AARectVertex {
505 GrPoint fPos;
506 GrPoint fOffset;
507 GrPoint fWidthHeight;
508};
509
510// Axis Aligned
511extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
512 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
513 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
514};
515
robertphillips@google.com42903302013-04-20 12:26:07 +0000516};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000517
518void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
519 GrDrawTarget* target,
520 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000521 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000522 GrDrawState* drawState = target->drawState();
523
524 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
525 combinedMatrix.mapPoints(&center, 1);
526
527 // compute transformed (0, 1) vector
528 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
529 dir.normalize();
530
531 // compute transformed (width, 0) and (0, height) vectors
532 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000533 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
534 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000535 };
536
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000537 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
538 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000539 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000540 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
541
542 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
543 if (!geo.succeeded()) {
544 GrPrintf("Failed to get space for vertices!\n");
545 return;
546 }
547
548 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
549
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000550 GrEffectRef* effect = GrRectEffect::Create();
551 static const int kRectAttrIndex = 1;
552 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000553 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000554
555 for (int i = 0; i < 4; ++i) {
556 verts[i].fCenter = center;
557 verts[i].fDir = dir;
558 verts[i].fWidthHeight.fX = newWidth;
559 verts[i].fWidthHeight.fY = newHeight;
560 }
561
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000562 SkRect devRect;
563 combinedMatrix.mapRect(&devRect, rect);
564
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000565 SkRect devBounds = {
566 devRect.fLeft - SK_ScalarHalf,
567 devRect.fTop - SK_ScalarHalf,
568 devRect.fRight + SK_ScalarHalf,
569 devRect.fBottom + SK_ScalarHalf
570 };
571
572 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
573 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
574 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
575 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
576
577 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
578 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
579 target->resetIndexSource();
580}
581
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000582void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
583 GrDrawTarget* target,
584 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000585 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000586 GrDrawState* drawState = target->drawState();
587 SkASSERT(combinedMatrix.rectStaysRect());
588
589 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
590 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
591
592 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
593 if (!geo.succeeded()) {
594 GrPrintf("Failed to get space for vertices!\n");
595 return;
596 }
597
598 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
599
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000600 GrEffectRef* effect = GrAlignedRectEffect::Create();
601 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000602 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000603
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000604 SkRect devRect;
605 combinedMatrix.mapRect(&devRect, rect);
606
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000607 SkRect devBounds = {
608 devRect.fLeft - SK_ScalarHalf,
609 devRect.fTop - SK_ScalarHalf,
610 devRect.fRight + SK_ScalarHalf,
611 devRect.fBottom + SK_ScalarHalf
612 };
613
614 GrPoint widthHeight = {
615 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
616 SkScalarHalf(devRect.height()) + SK_ScalarHalf
617 };
618
619 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
620 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
621 verts[0].fWidthHeight = widthHeight;
622
623 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
624 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
625 verts[1].fWidthHeight = widthHeight;
626
627 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
628 verts[2].fOffset = widthHeight;
629 verts[2].fWidthHeight = widthHeight;
630
631 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
632 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
633 verts[3].fWidthHeight = widthHeight;
634
635 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
636 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
637 target->resetIndexSource();
638}
639
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000640void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000641 GrDrawTarget* target,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000642 const GrRect& rect,
643 const SkMatrix& combinedMatrix,
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000644 const GrRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000645 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000646 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000647 GrVec devStrokeSize;
648 if (width > 0) {
649 devStrokeSize.set(width, width);
650 combinedMatrix.mapVectors(&devStrokeSize, 1);
651 devStrokeSize.setAbs(devStrokeSize);
652 } else {
653 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
654 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000655
robertphillips@google.com18136d12013-05-10 11:05:58 +0000656 const SkScalar dx = devStrokeSize.fX;
657 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000658 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
659 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000660
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000661 // Temporarily #if'ed out. We don't want to pass in the devRect but
662 // right now it is computed in GrContext::apply_aa_to_rect and we don't
663 // want to throw away the work
664#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000665 SkRect devRect;
666 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000667#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000668
bsalomon@google.com81712882012-11-01 17:12:34 +0000669 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000670 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000671 SkScalar w = devRect.width() - dx;
672 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000673 spare = GrMin(w, h);
674 }
675
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000676 GrRect devOutside(devRect);
677 devOutside.outset(rx, ry);
678
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000679 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000680 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000681 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000682 return;
683 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000684
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000685 SkRect devInside(devRect);
686 devInside.inset(rx, ry);
687
688 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
689}
690
691void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
692 GrDrawTarget* target,
693 const SkRect& devOutside,
694 const SkRect& devInside,
695 bool useVertexCoverage) {
696 GrDrawState* drawState = target->drawState();
697
robertphillips@google.com42903302013-04-20 12:26:07 +0000698 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000699
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000700 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000701 if (!geo.succeeded()) {
702 GrPrintf("Failed to get space for vertices!\n");
703 return;
704 }
705 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
706 if (NULL == indexBuffer) {
707 GrPrintf("Failed to create index buffer!\n");
708 return;
709 }
710
711 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000712 size_t vsize = drawState->getVertexSize();
713 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000714
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000715 // We create vertices for four nested rectangles. There are two ramps from 0 to full
716 // coverage, one on the exterior of the stroke and the other on the interior.
717 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000718 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
719 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
720 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
721 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
722
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000723 // outermost
724 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
725 set_inset_fan(fan1Pos, vsize, devOutside, SK_ScalarHalf, SK_ScalarHalf);
726 set_inset_fan(fan2Pos, vsize, devInside, -SK_ScalarHalf, -SK_ScalarHalf);
727 // innermost
728 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000729
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000730 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000731 verts += sizeof(GrPoint);
732 for (int i = 0; i < 4; ++i) {
733 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
734 }
735
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000736 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000737 GrColor innerColor;
738 if (useVertexCoverage) {
739 innerColor = 0xffffffff;
740 } else {
741 innerColor = target->getDrawState().getColor();
742 }
743 verts += 4 * vsize;
744 for (int i = 0; i < 8; ++i) {
745 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
746 }
747
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000748 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000749 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000750 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000751 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
752 }
753
754 target->setIndexSourceToBuffer(indexBuffer);
755 target->drawIndexed(kTriangles_GrPrimitiveType,
756 0, 0, 16, aaStrokeRectIndexCount());
757}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000758
759void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
760 GrDrawTarget* target,
761 const SkRect rects[2],
762 const SkMatrix& combinedMatrix,
763 bool useVertexCoverage) {
764 SkASSERT(combinedMatrix.rectStaysRect());
765 SkASSERT(!rects[1].isEmpty());
766
767 SkRect devOutside, devInside;
768 combinedMatrix.mapRect(&devOutside, rects[0]);
769 // can't call mapRect for devInside since it calls sort
770 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
771
772 if (devInside.isEmpty()) {
773 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
774 return;
775 }
776
777 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
778}