blob: 7fe0517f7ceb7a51cd2ac46f143dbdff4f74e3b9 [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
62 // TODO: compute these scale factors in the VS
63 // These scale factors adjust the coverage for < 1 pixel wide/high rects
64 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.z));\n",
65 fsRectName);
66 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.w));\n",
67 fsRectName);
68
69 // Compute the coverage for the rect's width
70 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.z-abs(%s.x)), 0.0, 1.0);\n",
71 fsRectName,
72 fsRectName);
73
74 // Compute the coverage for the rect's height and merge with the width
75 builder->fsCodeAppendf(
76 "\tcoverage = min(coverage, clamp(hScale*(%s.w-abs(%s.y)), 0.0, 1.0));\n",
77 fsRectName,
78 fsRectName);
79
80 SkString modulate;
81 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
82 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
83 }
84
85 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
86 return 0;
87 }
88
89 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
90
91 private:
92 typedef GrGLEffect INHERITED;
93 };
94
95
96private:
97 GrAlignedRectEffect() : GrEffect() {
98 this->addVertexAttrib(kVec4f_GrSLType);
99 }
100
101 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
102
103 GR_DECLARE_EFFECT_TEST;
104
105 typedef GrEffect INHERITED;
106};
107
108
109GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
110
111GrEffectRef* GrAlignedRectEffect::TestCreate(SkMWCRandom* random,
112 GrContext* context,
113 const GrDrawTargetCaps&,
114 GrTexture* textures[]) {
115 return GrAlignedRectEffect::Create();
116}
117
118///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000119class GrGLRectEffect;
120
121/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000122 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000123 * for an arbitrarily oriented rect. The rect is specified as:
124 * Center of the rect
125 * Unit vector point down the height of the rect
126 * Half width + 0.5
127 * Half height + 0.5
128 * The center and vector are stored in a vec4 varying ("RectEdge") with the
129 * center in the xy components and the vector in the zw components.
130 * The munged width and height are stored in a vec2 varying ("WidthHeight")
131 * with the width in x and the height in y.
132 */
133class GrRectEffect : public GrEffect {
134public:
135 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000136 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
137 gRectEffect->ref();
138 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000139 }
140
141 virtual ~GrRectEffect() {}
142
143 static const char* Name() { return "RectEdge"; }
144
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000145 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000146 uint32_t* validFlags) const SK_OVERRIDE {
147 *validFlags = 0;
148 }
149
150 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
151 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
152 }
153
154 class GLEffect : public GrGLEffect {
155 public:
156 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
157 : INHERITED (factory) {}
158
159 virtual void emitCode(GrGLShaderBuilder* builder,
160 const GrDrawEffect& drawEffect,
161 EffectKey key,
162 const char* outputColor,
163 const char* inputColor,
164 const TextureSamplerArray& samplers) SK_OVERRIDE {
165 // setup the varying for the center point and the unit vector
166 // that points down the height of the rect
167 const char *vsRectEdgeName, *fsRectEdgeName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000168 builder->addVarying(kVec4f_GrSLType, "RectEdge",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000169 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000170 const SkString* attr0Name =
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000171 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
172 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
173
174 // setup the varying for width/2+.5 and height/2+.5
175 const char *vsWidthHeightName, *fsWidthHeightName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000176 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000177 &vsWidthHeightName, &fsWidthHeightName);
178 const SkString* attr1Name =
179 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
180 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
181
182 // TODO: compute these scale factors in the VS
183 // These scale factors adjust the coverage for < 1 pixel wide/high rects
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000184 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000185 fsWidthHeightName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000186 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000187 fsWidthHeightName);
188
189 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000190 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000191 builder->fragmentPosition(), fsRectEdgeName);
192 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
193 fsRectEdgeName, fsRectEdgeName);
194 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n",
195 fsWidthHeightName);
196
197 // Compute the coverage for the rect's height and merge with the width
198 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
199 fsRectEdgeName);
200 builder->fsCodeAppendf(
201 "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n",
202 fsWidthHeightName);
203
204 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000205 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000206 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
207 }
208
209 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
210 return 0;
211 }
212
213 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
214
215 private:
216 typedef GrGLEffect INHERITED;
217 };
218
219
220private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000221 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000222 this->addVertexAttrib(kVec4f_GrSLType);
223 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000224 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000225 }
226
227 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
228
229 GR_DECLARE_EFFECT_TEST;
230
231 typedef GrEffect INHERITED;
232};
233
234
235GR_DEFINE_EFFECT_TEST(GrRectEffect);
236
237GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
238 GrContext* context,
239 const GrDrawTargetCaps&,
240 GrTexture* textures[]) {
241 return GrRectEffect::Create();
242}
243
244///////////////////////////////////////////////////////////////////////////////
245
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000246namespace {
247
robertphillips@google.com42903302013-04-20 12:26:07 +0000248extern const GrVertexAttrib gAARectCoverageAttribs[] = {
249 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
250 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
251};
252
253extern const GrVertexAttrib gAARectColorAttribs[] = {
254 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
255 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
256};
257
258static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
259 if (useCoverage) {
260 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
261 } else {
262 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
263 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000264}
265
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000266static void set_inset_fan(GrPoint* pts, size_t stride,
267 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
269 r.fRight - dx, r.fBottom - dy, stride);
270}
271
272};
273
274void GrAARectRenderer::reset() {
275 GrSafeSetNull(fAAFillRectIndexBuffer);
276 GrSafeSetNull(fAAStrokeRectIndexBuffer);
277}
278
robertphillips@google.com6d067302012-12-18 21:47:47 +0000279static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000280 0, 1, 5, 5, 4, 0,
281 1, 2, 6, 6, 5, 1,
282 2, 3, 7, 7, 6, 2,
283 3, 0, 4, 4, 7, 3,
284 4, 5, 6, 6, 7, 4,
285};
286
robertphillips@google.com6d067302012-12-18 21:47:47 +0000287static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
288static const int kVertsPerAAFillRect = 8;
289static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000290
291GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000292 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
293 sizeof(uint16_t) *
294 kNumAAFillRectsInIndexBuffer;
295
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000297 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000298 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000299 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
300 bool useTempData = (NULL == data);
301 if (useTempData) {
302 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
303 }
304 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
305 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
306 // the inner rect (for AA) and 2 for the inner rect.
307 int baseIdx = i * kIndicesPerAAFillRect;
308 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
309 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
310 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
311 }
312 }
313 if (useTempData) {
314 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
315 GrCrash("Can't get AA Fill Rect indices into buffer!");
316 }
317 SkDELETE_ARRAY(data);
318 } else {
319 fAAFillRectIndexBuffer->unlock();
320 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000321 }
322 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000323
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000324 return fAAFillRectIndexBuffer;
325}
326
robertphillips@google.com6d067302012-12-18 21:47:47 +0000327static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000328 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
329 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
330 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
331 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
332
333 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
334 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
335 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
336 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
337
338 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
339 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
340 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
341 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
342};
343
344int GrAARectRenderer::aaStrokeRectIndexCount() {
345 return GR_ARRAY_COUNT(gStrokeAARectIdx);
346}
347
348GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
349 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000350 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000351 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
352 if (NULL != fAAStrokeRectIndexBuffer) {
353#if GR_DEBUG
354 bool updated =
355#endif
356 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
357 sizeof(gStrokeAARectIdx));
358 GR_DEBUGASSERT(updated);
359 }
360 }
361 return fAAStrokeRectIndexBuffer;
362}
363
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000364void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
365 GrDrawTarget* target,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000366 const GrRect& rect,
367 const SkMatrix& combinedMatrix,
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000368 const GrRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000369 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000370 GrDrawState* drawState = target->drawState();
371
robertphillips@google.com42903302013-04-20 12:26:07 +0000372 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000373
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000374 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000375 if (!geo.succeeded()) {
376 GrPrintf("Failed to get space for vertices!\n");
377 return;
378 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000379
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000380 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
381 if (NULL == indexBuffer) {
382 GrPrintf("Failed to create index buffer!\n");
383 return;
384 }
385
386 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000387 size_t vsize = drawState->getVertexSize();
388 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000389
390 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
391 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
392
robertphillips@google.com908aed82013-05-28 13:16:20 +0000393 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
394 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
395
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000396 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000397 // Temporarily #if'ed out. We don't want to pass in the devRect but
398 // right now it is computed in GrContext::apply_aa_to_rect and we don't
399 // want to throw away the work
400#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000401 SkRect devRect;
402 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000403#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000404
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000405 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
robertphillips@google.com908aed82013-05-28 13:16:20 +0000406 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000407 } else {
408 // compute transformed (1, 0) and (0, 1) vectors
409 SkVector vec[2] = {
410 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
411 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
412 };
413
414 vec[0].normalize();
415 vec[0].scale(SK_ScalarHalf);
416 vec[1].normalize();
417 vec[1].scale(SK_ScalarHalf);
418
robertphillips@google.com91b71162013-05-10 14:09:54 +0000419 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000420 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
421 rect.fRight, rect.fBottom, vsize);
422 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
423
robertphillips@google.com91b71162013-05-10 14:09:54 +0000424 // Now create the inset points and then outset the original
425 // rotated points
426
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000427 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000428 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000429 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
430 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
431 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000432 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000433 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
434 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
435 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000436 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000437 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
438 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
439 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000440 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000441 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
442 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
443 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000444
445 verts += sizeof(GrPoint);
446 for (int i = 0; i < 4; ++i) {
447 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
448 }
449
robertphillips@google.com908aed82013-05-28 13:16:20 +0000450 int scale;
451 if (inset < SK_ScalarHalf) {
452 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
453 SkASSERT(scale >= 0 && scale <= 255);
454 } else {
455 scale = 0xff;
456 }
457
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000458 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000459 if (useVertexCoverage) {
robertphillips@google.com908aed82013-05-28 13:16:20 +0000460 innerColor = scale | (scale << 8) | (scale << 16) | (scale << 24);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000461 } else {
robertphillips@google.com908aed82013-05-28 13:16:20 +0000462 if (0xff == scale) {
463 innerColor = target->getDrawState().getColor();
464 } else {
465 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
466 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000467 }
468
469 verts += 4 * vsize;
470 for (int i = 0; i < 4; ++i) {
471 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
472 }
473
474 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000475 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
476 kVertsPerAAFillRect,
477 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000478 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000479}
480
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000481namespace {
482
483// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000484struct RectVertex {
485 GrPoint fPos;
486 GrPoint fCenter;
487 GrPoint fDir;
488 GrPoint fWidthHeight;
489};
490
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000491// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000492extern const GrVertexAttrib gAARectVertexAttribs[] = {
493 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
494 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
495 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
496};
497
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000498// Axis Aligned
499struct AARectVertex {
500 GrPoint fPos;
501 GrPoint fOffset;
502 GrPoint fWidthHeight;
503};
504
505// Axis Aligned
506extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
507 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
508 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
509};
510
robertphillips@google.com42903302013-04-20 12:26:07 +0000511};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000512
513void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
514 GrDrawTarget* target,
515 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000516 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000517 GrDrawState* drawState = target->drawState();
518
519 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
520 combinedMatrix.mapPoints(&center, 1);
521
522 // compute transformed (0, 1) vector
523 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
524 dir.normalize();
525
526 // compute transformed (width, 0) and (0, height) vectors
527 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000528 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
529 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000530 };
531
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000532 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
533 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000534 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000535 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
536
537 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
538 if (!geo.succeeded()) {
539 GrPrintf("Failed to get space for vertices!\n");
540 return;
541 }
542
543 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
544
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000545 GrEffectRef* effect = GrRectEffect::Create();
546 static const int kRectAttrIndex = 1;
547 static const int kWidthIndex = 2;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000548 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000549
550 for (int i = 0; i < 4; ++i) {
551 verts[i].fCenter = center;
552 verts[i].fDir = dir;
553 verts[i].fWidthHeight.fX = newWidth;
554 verts[i].fWidthHeight.fY = newHeight;
555 }
556
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000557 SkRect devRect;
558 combinedMatrix.mapRect(&devRect, rect);
559
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000560 SkRect devBounds = {
561 devRect.fLeft - SK_ScalarHalf,
562 devRect.fTop - SK_ScalarHalf,
563 devRect.fRight + SK_ScalarHalf,
564 devRect.fBottom + SK_ScalarHalf
565 };
566
567 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
568 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
569 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
570 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
571
572 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
573 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
574 target->resetIndexSource();
575}
576
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000577void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
578 GrDrawTarget* target,
579 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000580 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000581 GrDrawState* drawState = target->drawState();
582 SkASSERT(combinedMatrix.rectStaysRect());
583
584 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
585 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
586
587 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
588 if (!geo.succeeded()) {
589 GrPrintf("Failed to get space for vertices!\n");
590 return;
591 }
592
593 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
594
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000595 GrEffectRef* effect = GrAlignedRectEffect::Create();
596 static const int kOffsetIndex = 1;
bsalomon@google.comeb6879f2013-06-13 19:34:18 +0000597 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000598
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000599 SkRect devRect;
600 combinedMatrix.mapRect(&devRect, rect);
601
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000602 SkRect devBounds = {
603 devRect.fLeft - SK_ScalarHalf,
604 devRect.fTop - SK_ScalarHalf,
605 devRect.fRight + SK_ScalarHalf,
606 devRect.fBottom + SK_ScalarHalf
607 };
608
609 GrPoint widthHeight = {
610 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
611 SkScalarHalf(devRect.height()) + SK_ScalarHalf
612 };
613
614 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
615 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
616 verts[0].fWidthHeight = widthHeight;
617
618 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
619 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
620 verts[1].fWidthHeight = widthHeight;
621
622 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
623 verts[2].fOffset = widthHeight;
624 verts[2].fWidthHeight = widthHeight;
625
626 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
627 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
628 verts[3].fWidthHeight = widthHeight;
629
630 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
631 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
632 target->resetIndexSource();
633}
634
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000635void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000636 GrDrawTarget* target,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000637 const GrRect& rect,
638 const SkMatrix& combinedMatrix,
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000639 const GrRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000640 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000641 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000642 GrVec devStrokeSize;
643 if (width > 0) {
644 devStrokeSize.set(width, width);
645 combinedMatrix.mapVectors(&devStrokeSize, 1);
646 devStrokeSize.setAbs(devStrokeSize);
647 } else {
648 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
649 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000650
robertphillips@google.com18136d12013-05-10 11:05:58 +0000651 const SkScalar dx = devStrokeSize.fX;
652 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000653 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
654 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000655
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000656 // Temporarily #if'ed out. We don't want to pass in the devRect but
657 // right now it is computed in GrContext::apply_aa_to_rect and we don't
658 // want to throw away the work
659#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000660 SkRect devRect;
661 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000662#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000663
bsalomon@google.com81712882012-11-01 17:12:34 +0000664 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000665 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000666 SkScalar w = devRect.width() - dx;
667 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000668 spare = GrMin(w, h);
669 }
670
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000671 GrRect devOutside(devRect);
672 devOutside.outset(rx, ry);
673
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000674 if (spare <= 0) {
skia.committer@gmail.com845220b2013-05-20 11:51:35 +0000675 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000676 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000677 return;
678 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000679
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000680 SkRect devInside(devRect);
681 devInside.inset(rx, ry);
682
683 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
684}
685
686void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
687 GrDrawTarget* target,
688 const SkRect& devOutside,
689 const SkRect& devInside,
690 bool useVertexCoverage) {
691 GrDrawState* drawState = target->drawState();
692
robertphillips@google.com42903302013-04-20 12:26:07 +0000693 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000694
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000695 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000696 if (!geo.succeeded()) {
697 GrPrintf("Failed to get space for vertices!\n");
698 return;
699 }
700 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
701 if (NULL == indexBuffer) {
702 GrPrintf("Failed to create index buffer!\n");
703 return;
704 }
705
706 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000707 size_t vsize = drawState->getVertexSize();
708 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000709
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000710 // We create vertices for four nested rectangles. There are two ramps from 0 to full
711 // coverage, one on the exterior of the stroke and the other on the interior.
712 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000713 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
714 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
715 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
716 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
717
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000718 // outermost
719 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
720 set_inset_fan(fan1Pos, vsize, devOutside, SK_ScalarHalf, SK_ScalarHalf);
721 set_inset_fan(fan2Pos, vsize, devInside, -SK_ScalarHalf, -SK_ScalarHalf);
722 // innermost
723 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000724
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000725 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000726 verts += sizeof(GrPoint);
727 for (int i = 0; i < 4; ++i) {
728 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
729 }
730
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000731 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000732 GrColor innerColor;
733 if (useVertexCoverage) {
734 innerColor = 0xffffffff;
735 } else {
736 innerColor = target->getDrawState().getColor();
737 }
738 verts += 4 * vsize;
739 for (int i = 0; i < 8; ++i) {
740 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
741 }
742
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000743 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000744 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000745 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000746 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
747 }
748
749 target->setIndexSourceToBuffer(indexBuffer);
750 target->drawIndexed(kTriangles_GrPrimitiveType,
751 0, 0, 16, aaStrokeRectIndexCount());
752}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000753
754void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
755 GrDrawTarget* target,
756 const SkRect rects[2],
757 const SkMatrix& combinedMatrix,
758 bool useVertexCoverage) {
759 SkASSERT(combinedMatrix.rectStaysRect());
760 SkASSERT(!rects[1].isEmpty());
761
762 SkRect devOutside, devInside;
763 combinedMatrix.mapRect(&devOutside, rects[0]);
764 // can't call mapRect for devInside since it calls sort
765 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
766
767 if (devInside.isEmpty()) {
768 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
769 return;
770 }
771
772 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
773}