blob: cae3b6f5d6085f8acd0dda813861e94fe4d4c8ca [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.comb19cb7f2013-05-02 15:37:20 +0000367 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000368 GrDrawState* drawState = target->drawState();
369
robertphillips@google.com42903302013-04-20 12:26:07 +0000370 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000371
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000372 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000373 if (!geo.succeeded()) {
374 GrPrintf("Failed to get space for vertices!\n");
375 return;
376 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000377
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000378 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
379 if (NULL == indexBuffer) {
380 GrPrintf("Failed to create index buffer!\n");
381 return;
382 }
383
384 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000385 size_t vsize = drawState->getVertexSize();
386 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000387
388 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
389 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
390
robertphillips@google.com18136d12013-05-10 11:05:58 +0000391 SkRect devRect;
392 combinedMatrix.mapRect(&devRect, rect);
393
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000394 if (combinedMatrix.rectStaysRect()) {
395 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
396 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
397 } else {
398 // compute transformed (1, 0) and (0, 1) vectors
399 SkVector vec[2] = {
400 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
401 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
402 };
403
404 vec[0].normalize();
405 vec[0].scale(SK_ScalarHalf);
406 vec[1].normalize();
407 vec[1].scale(SK_ScalarHalf);
408
409 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
410 rect.fRight, rect.fBottom, vsize);
411 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
412
413 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000414 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000415 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
416 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
417 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000418 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000419 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
420 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
421 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000422 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000423 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
424 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
425 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000426 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000427 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
428 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
429 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000430
431 verts += sizeof(GrPoint);
432 for (int i = 0; i < 4; ++i) {
433 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
434 }
435
436 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000437 if (useVertexCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000438 innerColor = 0xffffffff;
439 } else {
440 innerColor = target->getDrawState().getColor();
441 }
442
443 verts += 4 * vsize;
444 for (int i = 0; i < 4; ++i) {
445 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
446 }
447
448 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000449 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
450 kVertsPerAAFillRect,
451 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000452 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000453}
454
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000455namespace {
456
457// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000458struct RectVertex {
459 GrPoint fPos;
460 GrPoint fCenter;
461 GrPoint fDir;
462 GrPoint fWidthHeight;
463};
464
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000465// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000466extern const GrVertexAttrib gAARectVertexAttribs[] = {
467 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
468 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
469 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
470};
471
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000472// Axis Aligned
473struct AARectVertex {
474 GrPoint fPos;
475 GrPoint fOffset;
476 GrPoint fWidthHeight;
477};
478
479// Axis Aligned
480extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
481 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
482 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
483};
484
robertphillips@google.com42903302013-04-20 12:26:07 +0000485};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000486
487void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
488 GrDrawTarget* target,
489 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000490 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000491 GrDrawState* drawState = target->drawState();
492
493 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
494 combinedMatrix.mapPoints(&center, 1);
495
496 // compute transformed (0, 1) vector
497 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
498 dir.normalize();
499
500 // compute transformed (width, 0) and (0, height) vectors
501 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000502 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
503 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000504 };
505
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000506 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
507 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000508 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000509 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
510
511 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
512 if (!geo.succeeded()) {
513 GrPrintf("Failed to get space for vertices!\n");
514 return;
515 }
516
517 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
518
519 enum {
520 // the edge effects share this stage with glyph rendering
521 // (kGlyphMaskStage in GrTextContext) && SW path rendering
522 // (kPathMaskStage in GrSWMaskHelper)
523 kEdgeEffectStage = GrPaint::kTotalStages,
524 };
525
526 GrEffectRef* effect = GrRectEffect::Create();
527 static const int kRectAttrIndex = 1;
528 static const int kWidthIndex = 2;
529 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
530
531 for (int i = 0; i < 4; ++i) {
532 verts[i].fCenter = center;
533 verts[i].fDir = dir;
534 verts[i].fWidthHeight.fX = newWidth;
535 verts[i].fWidthHeight.fY = newHeight;
536 }
537
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000538 SkRect devRect;
539 combinedMatrix.mapRect(&devRect, rect);
540
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000541 SkRect devBounds = {
542 devRect.fLeft - SK_ScalarHalf,
543 devRect.fTop - SK_ScalarHalf,
544 devRect.fRight + SK_ScalarHalf,
545 devRect.fBottom + SK_ScalarHalf
546 };
547
548 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
549 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
550 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
551 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
552
553 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
554 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
555 target->resetIndexSource();
556}
557
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000558void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
559 GrDrawTarget* target,
560 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000561 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000562 GrDrawState* drawState = target->drawState();
563 SkASSERT(combinedMatrix.rectStaysRect());
564
565 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
566 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
567
568 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
569 if (!geo.succeeded()) {
570 GrPrintf("Failed to get space for vertices!\n");
571 return;
572 }
573
574 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
575
576 enum {
577 // the edge effects share this stage with glyph rendering
578 // (kGlyphMaskStage in GrTextContext) && SW path rendering
579 // (kPathMaskStage in GrSWMaskHelper)
580 kEdgeEffectStage = GrPaint::kTotalStages,
581 };
582
583 GrEffectRef* effect = GrAlignedRectEffect::Create();
584 static const int kOffsetIndex = 1;
585 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
586
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000587 SkRect devRect;
588 combinedMatrix.mapRect(&devRect, rect);
589
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000590 SkRect devBounds = {
591 devRect.fLeft - SK_ScalarHalf,
592 devRect.fTop - SK_ScalarHalf,
593 devRect.fRight + SK_ScalarHalf,
594 devRect.fBottom + SK_ScalarHalf
595 };
596
597 GrPoint widthHeight = {
598 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
599 SkScalarHalf(devRect.height()) + SK_ScalarHalf
600 };
601
602 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
603 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
604 verts[0].fWidthHeight = widthHeight;
605
606 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
607 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
608 verts[1].fWidthHeight = widthHeight;
609
610 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
611 verts[2].fOffset = widthHeight;
612 verts[2].fWidthHeight = widthHeight;
613
614 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
615 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
616 verts[3].fWidthHeight = widthHeight;
617
618 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
619 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
620 target->resetIndexSource();
621}
622
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000623void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000624 GrDrawTarget* target,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000625 const GrRect& rect,
626 const SkMatrix& combinedMatrix,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000627 const GrVec& devStrokeSize,
628 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000629 GrDrawState* drawState = target->drawState();
630
robertphillips@google.com18136d12013-05-10 11:05:58 +0000631 const SkScalar dx = devStrokeSize.fX;
632 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000633 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
634 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000635
robertphillips@google.com18136d12013-05-10 11:05:58 +0000636 SkRect devRect;
637 combinedMatrix.mapRect(&devRect, rect);
638
bsalomon@google.com81712882012-11-01 17:12:34 +0000639 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000640 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000641 SkScalar w = devRect.width() - dx;
642 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000643 spare = GrMin(w, h);
644 }
645
646 if (spare <= 0) {
robertphillips@google.com18136d12013-05-10 11:05:58 +0000647 devRect.inset(-rx, -ry);
648 this->fillAARect(gpu, target, devRect, SkMatrix::I(), useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000649 return;
650 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000651
robertphillips@google.com42903302013-04-20 12:26:07 +0000652 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000653
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000654 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000655 if (!geo.succeeded()) {
656 GrPrintf("Failed to get space for vertices!\n");
657 return;
658 }
659 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
660 if (NULL == indexBuffer) {
661 GrPrintf("Failed to create index buffer!\n");
662 return;
663 }
664
665 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000666 size_t vsize = drawState->getVertexSize();
667 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000668
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000669 // We create vertices for four nested rectangles. There are two ramps from 0 to full
670 // coverage, one on the exterior of the stroke and the other on the interior.
671 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000672 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
673 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
674 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
675 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
676
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000677 set_inset_fan(fan0Pos, vsize, devRect,
678 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
679 set_inset_fan(fan1Pos, vsize, devRect,
680 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
681 set_inset_fan(fan2Pos, vsize, devRect,
682 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
683 set_inset_fan(fan3Pos, vsize, devRect,
684 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000685
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000686 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000687 verts += sizeof(GrPoint);
688 for (int i = 0; i < 4; ++i) {
689 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
690 }
691
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000692 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000693 GrColor innerColor;
694 if (useVertexCoverage) {
695 innerColor = 0xffffffff;
696 } else {
697 innerColor = target->getDrawState().getColor();
698 }
699 verts += 4 * vsize;
700 for (int i = 0; i < 8; ++i) {
701 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
702 }
703
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000704 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000705 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000706 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000707 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
708 }
709
710 target->setIndexSourceToBuffer(indexBuffer);
711 target->drawIndexed(kTriangles_GrPrimitiveType,
712 0, 0, 16, aaStrokeRectIndexCount());
713}