blob: bef5ddb620a4aacb28a4e955870172f5bc168eb6 [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.comb19cb7f2013-05-02 15:37:20 +000016///////////////////////////////////////////////////////////////////////////////
17class GrGLAlignedRectEffect;
18
19// Axis Aligned special case
20class GrAlignedRectEffect : public GrEffect {
21public:
22 static GrEffectRef* Create() {
23 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
24 gAlignedRectEffect->ref();
25 return gAlignedRectEffect;
26 }
27
28 virtual ~GrAlignedRectEffect() {}
29
30 static const char* Name() { return "AlignedRectEdge"; }
31
32 virtual void getConstantColorComponents(GrColor* color,
33 uint32_t* validFlags) const SK_OVERRIDE {
34 *validFlags = 0;
35 }
36
37 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
38 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
39 }
40
41 class GLEffect : public GrGLEffect {
42 public:
43 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
44 : INHERITED (factory) {}
45
46 virtual void emitCode(GrGLShaderBuilder* builder,
47 const GrDrawEffect& drawEffect,
48 EffectKey key,
49 const char* outputColor,
50 const char* inputColor,
51 const TextureSamplerArray& samplers) SK_OVERRIDE {
52 // setup the varying for the Axis aligned rect effect
53 // xy -> interpolated offset
54 // zw -> w/2+0.5, h/2+0.5
55 const char *vsRectName, *fsRectName;
56 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
57 const SkString* attr0Name =
58 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
59 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
60
61 // TODO: compute these scale factors in the VS
62 // These scale factors adjust the coverage for < 1 pixel wide/high rects
63 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.z));\n",
64 fsRectName);
65 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.w));\n",
66 fsRectName);
67
68 // Compute the coverage for the rect's width
69 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.z-abs(%s.x)), 0.0, 1.0);\n",
70 fsRectName,
71 fsRectName);
72
73 // Compute the coverage for the rect's height and merge with the width
74 builder->fsCodeAppendf(
75 "\tcoverage = min(coverage, clamp(hScale*(%s.w-abs(%s.y)), 0.0, 1.0));\n",
76 fsRectName,
77 fsRectName);
78
79 SkString modulate;
80 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
81 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
82 }
83
84 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
85 return 0;
86 }
87
88 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
89
90 private:
91 typedef GrGLEffect INHERITED;
92 };
93
94
95private:
96 GrAlignedRectEffect() : GrEffect() {
97 this->addVertexAttrib(kVec4f_GrSLType);
98 }
99
100 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
101
102 GR_DECLARE_EFFECT_TEST;
103
104 typedef GrEffect INHERITED;
105};
106
107
108GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
109
110GrEffectRef* GrAlignedRectEffect::TestCreate(SkMWCRandom* random,
111 GrContext* context,
112 const GrDrawTargetCaps&,
113 GrTexture* textures[]) {
114 return GrAlignedRectEffect::Create();
115}
116
117///////////////////////////////////////////////////////////////////////////////
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000118class GrGLRectEffect;
119
120/**
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000121 * The output of this effect is a modulation of the input color and coverage
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000122 * for an arbitrarily oriented rect. The rect is specified as:
123 * Center of the rect
124 * Unit vector point down the height of the rect
125 * Half width + 0.5
126 * Half height + 0.5
127 * The center and vector are stored in a vec4 varying ("RectEdge") with the
128 * center in the xy components and the vector in the zw components.
129 * The munged width and height are stored in a vec2 varying ("WidthHeight")
130 * with the width in x and the height in y.
131 */
132class GrRectEffect : public GrEffect {
133public:
134 static GrEffectRef* Create() {
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000135 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
136 gRectEffect->ref();
137 return gRectEffect;
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000138 }
139
140 virtual ~GrRectEffect() {}
141
142 static const char* Name() { return "RectEdge"; }
143
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000144 virtual void getConstantColorComponents(GrColor* color,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000145 uint32_t* validFlags) const SK_OVERRIDE {
146 *validFlags = 0;
147 }
148
149 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
150 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
151 }
152
153 class GLEffect : public GrGLEffect {
154 public:
155 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
156 : INHERITED (factory) {}
157
158 virtual void emitCode(GrGLShaderBuilder* builder,
159 const GrDrawEffect& drawEffect,
160 EffectKey key,
161 const char* outputColor,
162 const char* inputColor,
163 const TextureSamplerArray& samplers) SK_OVERRIDE {
164 // setup the varying for the center point and the unit vector
165 // that points down the height of the rect
166 const char *vsRectEdgeName, *fsRectEdgeName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000167 builder->addVarying(kVec4f_GrSLType, "RectEdge",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000168 &vsRectEdgeName, &fsRectEdgeName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000169 const SkString* attr0Name =
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000170 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
171 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
172
173 // setup the varying for width/2+.5 and height/2+.5
174 const char *vsWidthHeightName, *fsWidthHeightName;
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000175 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000176 &vsWidthHeightName, &fsWidthHeightName);
177 const SkString* attr1Name =
178 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
179 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
180
181 // TODO: compute these scale factors in the VS
182 // These scale factors adjust the coverage for < 1 pixel wide/high rects
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000183 builder->fsCodeAppendf("\tfloat wScale = max(1.0, 2.0/(0.5+%s.x));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000184 fsWidthHeightName);
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000185 builder->fsCodeAppendf("\tfloat hScale = max(1.0, 2.0/(0.5+%s.y));\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000186 fsWidthHeightName);
187
188 // Compute the coverage for the rect's width
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000189 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000190 builder->fragmentPosition(), fsRectEdgeName);
191 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
192 fsRectEdgeName, fsRectEdgeName);
193 builder->fsCodeAppendf("\tfloat coverage = clamp(wScale*(%s.x-perpDot), 0.0, 1.0);\n",
194 fsWidthHeightName);
195
196 // Compute the coverage for the rect's height and merge with the width
197 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
198 fsRectEdgeName);
199 builder->fsCodeAppendf(
200 "\tcoverage = min(coverage, clamp(hScale*(%s.y-perpDot), 0.0, 1.0));\n",
201 fsWidthHeightName);
202
203 SkString modulate;
bsalomon@google.com018f1792013-04-18 19:36:09 +0000204 GrGLSLModulatef<4>(&modulate, inputColor, "coverage");
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000205 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
206 }
207
208 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
209 return 0;
210 }
211
212 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
213
214 private:
215 typedef GrGLEffect INHERITED;
216 };
217
218
219private:
robertphillips@google.com59dd7162013-04-09 14:08:15 +0000220 GrRectEffect() : GrEffect() {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000221 this->addVertexAttrib(kVec4f_GrSLType);
222 this->addVertexAttrib(kVec2f_GrSLType);
commit-bot@chromium.org8d47ddc2013-05-09 14:55:46 +0000223 this->setWillReadFragmentPosition();
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000224 }
225
226 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
227
228 GR_DECLARE_EFFECT_TEST;
229
230 typedef GrEffect INHERITED;
231};
232
233
234GR_DEFINE_EFFECT_TEST(GrRectEffect);
235
236GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
237 GrContext* context,
238 const GrDrawTargetCaps&,
239 GrTexture* textures[]) {
240 return GrRectEffect::Create();
241}
242
243///////////////////////////////////////////////////////////////////////////////
244
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000245namespace {
246
robertphillips@google.com42903302013-04-20 12:26:07 +0000247extern const GrVertexAttrib gAARectCoverageAttribs[] = {
248 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
249 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
250};
251
252extern const GrVertexAttrib gAARectColorAttribs[] = {
253 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
254 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
255};
256
257static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
258 if (useCoverage) {
259 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
260 } else {
261 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
262 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000263}
264
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000265static void set_inset_fan(GrPoint* pts, size_t stride,
266 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
268 r.fRight - dx, r.fBottom - dy, stride);
269}
270
271};
272
273void GrAARectRenderer::reset() {
274 GrSafeSetNull(fAAFillRectIndexBuffer);
275 GrSafeSetNull(fAAStrokeRectIndexBuffer);
276}
277
robertphillips@google.com6d067302012-12-18 21:47:47 +0000278static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000279 0, 1, 5, 5, 4, 0,
280 1, 2, 6, 6, 5, 1,
281 2, 3, 7, 7, 6, 2,
282 3, 0, 4, 4, 7, 3,
283 4, 5, 6, 6, 7, 4,
284};
285
robertphillips@google.com6d067302012-12-18 21:47:47 +0000286static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
287static const int kVertsPerAAFillRect = 8;
288static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000289
290GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000291 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
292 sizeof(uint16_t) *
293 kNumAAFillRectsInIndexBuffer;
294
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000295 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000296 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000297 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000298 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
299 bool useTempData = (NULL == data);
300 if (useTempData) {
301 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
302 }
303 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
304 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
305 // the inner rect (for AA) and 2 for the inner rect.
306 int baseIdx = i * kIndicesPerAAFillRect;
307 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
308 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
309 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
310 }
311 }
312 if (useTempData) {
313 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
314 GrCrash("Can't get AA Fill Rect indices into buffer!");
315 }
316 SkDELETE_ARRAY(data);
317 } else {
318 fAAFillRectIndexBuffer->unlock();
319 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000320 }
321 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000322
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000323 return fAAFillRectIndexBuffer;
324}
325
robertphillips@google.com6d067302012-12-18 21:47:47 +0000326static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000327 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
328 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
329 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
330 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
331
332 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
333 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
334 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
335 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
336
337 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
338 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
339 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
340 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
341};
342
343int GrAARectRenderer::aaStrokeRectIndexCount() {
344 return GR_ARRAY_COUNT(gStrokeAARectIdx);
345}
346
347GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
348 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000349 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000350 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
351 if (NULL != fAAStrokeRectIndexBuffer) {
352#if GR_DEBUG
353 bool updated =
354#endif
355 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
356 sizeof(gStrokeAARectIdx));
357 GR_DEBUGASSERT(updated);
358 }
359 }
360 return fAAStrokeRectIndexBuffer;
361}
362
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000363void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
364 GrDrawTarget* target,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000365 const GrRect& rect,
366 const SkMatrix& combinedMatrix,
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000367 const GrRect& devRect,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000368 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000369 GrDrawState* drawState = target->drawState();
370
robertphillips@google.com42903302013-04-20 12:26:07 +0000371 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000372
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000373 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000374 if (!geo.succeeded()) {
375 GrPrintf("Failed to get space for vertices!\n");
376 return;
377 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000378
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000379 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
380 if (NULL == indexBuffer) {
381 GrPrintf("Failed to create index buffer!\n");
382 return;
383 }
384
385 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000386 size_t vsize = drawState->getVertexSize();
387 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000388
389 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
390 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
391
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000392 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000393 // Temporarily #if'ed out. We don't want to pass in the devRect but
394 // right now it is computed in GrContext::apply_aa_to_rect and we don't
395 // want to throw away the work
396#if 0
robertphillips@google.com91b71162013-05-10 14:09:54 +0000397 SkRect devRect;
398 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000399#endif
robertphillips@google.com91b71162013-05-10 14:09:54 +0000400
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000401 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
402 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
403 } else {
404 // compute transformed (1, 0) and (0, 1) vectors
405 SkVector vec[2] = {
406 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
407 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
408 };
409
410 vec[0].normalize();
411 vec[0].scale(SK_ScalarHalf);
412 vec[1].normalize();
413 vec[1].scale(SK_ScalarHalf);
414
robertphillips@google.com91b71162013-05-10 14:09:54 +0000415 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000416 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
417 rect.fRight, rect.fBottom, vsize);
418 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
419
robertphillips@google.com91b71162013-05-10 14:09:54 +0000420 // Now create the inset points and then outset the original
421 // rotated points
422
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000423 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000424 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000425 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
426 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
427 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000428 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000429 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
430 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
431 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000432 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000433 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
434 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
435 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000436 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000437 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
438 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
439 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000440
441 verts += sizeof(GrPoint);
442 for (int i = 0; i < 4; ++i) {
443 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
444 }
445
446 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000447 if (useVertexCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000448 innerColor = 0xffffffff;
449 } else {
450 innerColor = target->getDrawState().getColor();
451 }
452
453 verts += 4 * vsize;
454 for (int i = 0; i < 4; ++i) {
455 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
456 }
457
458 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000459 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
460 kVertsPerAAFillRect,
461 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000462 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000463}
464
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000465namespace {
466
467// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000468struct RectVertex {
469 GrPoint fPos;
470 GrPoint fCenter;
471 GrPoint fDir;
472 GrPoint fWidthHeight;
473};
474
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000475// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000476extern const GrVertexAttrib gAARectVertexAttribs[] = {
477 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
478 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
479 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
480};
481
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000482// Axis Aligned
483struct AARectVertex {
484 GrPoint fPos;
485 GrPoint fOffset;
486 GrPoint fWidthHeight;
487};
488
489// Axis Aligned
490extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
491 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
492 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
493};
494
robertphillips@google.com42903302013-04-20 12:26:07 +0000495};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000496
497void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
498 GrDrawTarget* target,
499 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000500 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000501 GrDrawState* drawState = target->drawState();
502
503 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
504 combinedMatrix.mapPoints(&center, 1);
505
506 // compute transformed (0, 1) vector
507 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
508 dir.normalize();
509
510 // compute transformed (width, 0) and (0, height) vectors
511 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000512 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
513 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000514 };
515
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000516 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
517 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000518 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000519 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
520
521 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
522 if (!geo.succeeded()) {
523 GrPrintf("Failed to get space for vertices!\n");
524 return;
525 }
526
527 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
528
529 enum {
530 // the edge effects share this stage with glyph rendering
531 // (kGlyphMaskStage in GrTextContext) && SW path rendering
532 // (kPathMaskStage in GrSWMaskHelper)
533 kEdgeEffectStage = GrPaint::kTotalStages,
534 };
535
536 GrEffectRef* effect = GrRectEffect::Create();
537 static const int kRectAttrIndex = 1;
538 static const int kWidthIndex = 2;
539 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
540
541 for (int i = 0; i < 4; ++i) {
542 verts[i].fCenter = center;
543 verts[i].fDir = dir;
544 verts[i].fWidthHeight.fX = newWidth;
545 verts[i].fWidthHeight.fY = newHeight;
546 }
547
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000548 SkRect devRect;
549 combinedMatrix.mapRect(&devRect, rect);
550
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000551 SkRect devBounds = {
552 devRect.fLeft - SK_ScalarHalf,
553 devRect.fTop - SK_ScalarHalf,
554 devRect.fRight + SK_ScalarHalf,
555 devRect.fBottom + SK_ScalarHalf
556 };
557
558 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
559 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
560 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
561 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
562
563 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
564 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
565 target->resetIndexSource();
566}
567
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000568void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
569 GrDrawTarget* target,
570 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000571 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000572 GrDrawState* drawState = target->drawState();
573 SkASSERT(combinedMatrix.rectStaysRect());
574
575 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
576 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
577
578 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
579 if (!geo.succeeded()) {
580 GrPrintf("Failed to get space for vertices!\n");
581 return;
582 }
583
584 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
585
586 enum {
587 // the edge effects share this stage with glyph rendering
588 // (kGlyphMaskStage in GrTextContext) && SW path rendering
589 // (kPathMaskStage in GrSWMaskHelper)
590 kEdgeEffectStage = GrPaint::kTotalStages,
591 };
592
593 GrEffectRef* effect = GrAlignedRectEffect::Create();
594 static const int kOffsetIndex = 1;
595 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
596
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000597 SkRect devRect;
598 combinedMatrix.mapRect(&devRect, rect);
599
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000600 SkRect devBounds = {
601 devRect.fLeft - SK_ScalarHalf,
602 devRect.fTop - SK_ScalarHalf,
603 devRect.fRight + SK_ScalarHalf,
604 devRect.fBottom + SK_ScalarHalf
605 };
606
607 GrPoint widthHeight = {
608 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
609 SkScalarHalf(devRect.height()) + SK_ScalarHalf
610 };
611
612 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
613 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
614 verts[0].fWidthHeight = widthHeight;
615
616 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
617 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
618 verts[1].fWidthHeight = widthHeight;
619
620 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
621 verts[2].fOffset = widthHeight;
622 verts[2].fWidthHeight = widthHeight;
623
624 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
625 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
626 verts[3].fWidthHeight = widthHeight;
627
628 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
629 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
630 target->resetIndexSource();
631}
632
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000633void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000634 GrDrawTarget* target,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000635 const GrRect& rect,
636 const SkMatrix& combinedMatrix,
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000637 const GrRect& devRect,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000638 SkScalar width,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000639 bool useVertexCoverage) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000640 GrVec devStrokeSize;
641 if (width > 0) {
642 devStrokeSize.set(width, width);
643 combinedMatrix.mapVectors(&devStrokeSize, 1);
644 devStrokeSize.setAbs(devStrokeSize);
645 } else {
646 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
647 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000648
robertphillips@google.com18136d12013-05-10 11:05:58 +0000649 const SkScalar dx = devStrokeSize.fX;
650 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000651 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
652 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000653
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000654 // Temporarily #if'ed out. We don't want to pass in the devRect but
655 // right now it is computed in GrContext::apply_aa_to_rect and we don't
656 // want to throw away the work
657#if 0
robertphillips@google.com18136d12013-05-10 11:05:58 +0000658 SkRect devRect;
659 combinedMatrix.mapRect(&devRect, rect);
robertphillips@google.comafd1cba2013-05-14 19:47:47 +0000660#endif
robertphillips@google.com18136d12013-05-10 11:05:58 +0000661
bsalomon@google.com81712882012-11-01 17:12:34 +0000662 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000663 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000664 SkScalar w = devRect.width() - dx;
665 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000666 spare = GrMin(w, h);
667 }
668
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000669 GrRect devOutside(devRect);
670 devOutside.outset(rx, ry);
671
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000672 if (spare <= 0) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000673 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
674 devOutside, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000675 return;
676 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000677
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000678 SkRect devInside(devRect);
679 devInside.inset(rx, ry);
680
681 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
682}
683
684void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
685 GrDrawTarget* target,
686 const SkRect& devOutside,
687 const SkRect& devInside,
688 bool useVertexCoverage) {
689 GrDrawState* drawState = target->drawState();
690
robertphillips@google.com42903302013-04-20 12:26:07 +0000691 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000692
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000693 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000694 if (!geo.succeeded()) {
695 GrPrintf("Failed to get space for vertices!\n");
696 return;
697 }
698 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
699 if (NULL == indexBuffer) {
700 GrPrintf("Failed to create index buffer!\n");
701 return;
702 }
703
704 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000705 size_t vsize = drawState->getVertexSize();
706 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000707
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000708 // We create vertices for four nested rectangles. There are two ramps from 0 to full
709 // coverage, one on the exterior of the stroke and the other on the interior.
710 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000711 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
712 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
713 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
714 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
715
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000716 // outermost
717 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
718 set_inset_fan(fan1Pos, vsize, devOutside, SK_ScalarHalf, SK_ScalarHalf);
719 set_inset_fan(fan2Pos, vsize, devInside, -SK_ScalarHalf, -SK_ScalarHalf);
720 // innermost
721 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000722
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000723 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000724 verts += sizeof(GrPoint);
725 for (int i = 0; i < 4; ++i) {
726 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
727 }
728
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000729 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000730 GrColor innerColor;
731 if (useVertexCoverage) {
732 innerColor = 0xffffffff;
733 } else {
734 innerColor = target->getDrawState().getColor();
735 }
736 verts += 4 * vsize;
737 for (int i = 0; i < 8; ++i) {
738 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
739 }
740
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000741 // The innermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000742 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000743 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000744 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
745 }
746
747 target->setIndexSourceToBuffer(indexBuffer);
748 target->drawIndexed(kTriangles_GrPrimitiveType,
749 0, 0, 16, aaStrokeRectIndexCount());
750}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000751
752void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
753 GrDrawTarget* target,
754 const SkRect rects[2],
755 const SkMatrix& combinedMatrix,
756 bool useVertexCoverage) {
757 SkASSERT(combinedMatrix.rectStaysRect());
758 SkASSERT(!rects[1].isEmpty());
759
760 SkRect devOutside, devInside;
761 combinedMatrix.mapRect(&devOutside, rects[0]);
762 // can't call mapRect for devInside since it calls sort
763 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
764
765 if (devInside.isEmpty()) {
766 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
767 return;
768 }
769
770 this->geometryStrokeAARect(gpu, target, devOutside, devInside, useVertexCoverage);
771}