blob: 883305ef686301ffaceeee175aeeafec3f2fe3ab [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,
490 const SkMatrix& combinedMatrix,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000491 const GrRect& devRect) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000492 GrDrawState* drawState = target->drawState();
493
494 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
495 combinedMatrix.mapPoints(&center, 1);
496
497 // compute transformed (0, 1) vector
498 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
499 dir.normalize();
500
501 // compute transformed (width, 0) and (0, height) vectors
502 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000503 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
504 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000505 };
506
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000507 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
508 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000509 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000510 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
511
512 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
513 if (!geo.succeeded()) {
514 GrPrintf("Failed to get space for vertices!\n");
515 return;
516 }
517
518 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
519
520 enum {
521 // the edge effects share this stage with glyph rendering
522 // (kGlyphMaskStage in GrTextContext) && SW path rendering
523 // (kPathMaskStage in GrSWMaskHelper)
524 kEdgeEffectStage = GrPaint::kTotalStages,
525 };
526
527 GrEffectRef* effect = GrRectEffect::Create();
528 static const int kRectAttrIndex = 1;
529 static const int kWidthIndex = 2;
530 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
531
532 for (int i = 0; i < 4; ++i) {
533 verts[i].fCenter = center;
534 verts[i].fDir = dir;
535 verts[i].fWidthHeight.fX = newWidth;
536 verts[i].fWidthHeight.fY = newHeight;
537 }
538
539 SkRect devBounds = {
540 devRect.fLeft - SK_ScalarHalf,
541 devRect.fTop - SK_ScalarHalf,
542 devRect.fRight + SK_ScalarHalf,
543 devRect.fBottom + SK_ScalarHalf
544 };
545
546 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
547 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
548 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
549 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
550
551 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
552 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
553 target->resetIndexSource();
554}
555
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000556void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
557 GrDrawTarget* target,
558 const GrRect& rect,
559 const SkMatrix& combinedMatrix,
560 const GrRect& devRect) {
561 GrDrawState* drawState = target->drawState();
562 SkASSERT(combinedMatrix.rectStaysRect());
563
564 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
565 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
566
567 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
568 if (!geo.succeeded()) {
569 GrPrintf("Failed to get space for vertices!\n");
570 return;
571 }
572
573 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
574
575 enum {
576 // the edge effects share this stage with glyph rendering
577 // (kGlyphMaskStage in GrTextContext) && SW path rendering
578 // (kPathMaskStage in GrSWMaskHelper)
579 kEdgeEffectStage = GrPaint::kTotalStages,
580 };
581
582 GrEffectRef* effect = GrAlignedRectEffect::Create();
583 static const int kOffsetIndex = 1;
584 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
585
586 SkRect devBounds = {
587 devRect.fLeft - SK_ScalarHalf,
588 devRect.fTop - SK_ScalarHalf,
589 devRect.fRight + SK_ScalarHalf,
590 devRect.fBottom + SK_ScalarHalf
591 };
592
593 GrPoint widthHeight = {
594 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
595 SkScalarHalf(devRect.height()) + SK_ScalarHalf
596 };
597
598 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
599 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
600 verts[0].fWidthHeight = widthHeight;
601
602 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
603 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
604 verts[1].fWidthHeight = widthHeight;
605
606 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
607 verts[2].fOffset = widthHeight;
608 verts[2].fWidthHeight = widthHeight;
609
610 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
611 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
612 verts[3].fWidthHeight = widthHeight;
613
614 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
615 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
616 target->resetIndexSource();
617}
618
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000619void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000620 GrDrawTarget* target,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000621 const GrRect& rect,
622 const SkMatrix& combinedMatrix,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000623 const GrVec& devStrokeSize,
624 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000625 GrDrawState* drawState = target->drawState();
626
robertphillips@google.com18136d12013-05-10 11:05:58 +0000627 const SkScalar dx = devStrokeSize.fX;
628 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000629 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
630 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000631
robertphillips@google.com18136d12013-05-10 11:05:58 +0000632 SkRect devRect;
633 combinedMatrix.mapRect(&devRect, rect);
634
bsalomon@google.com81712882012-11-01 17:12:34 +0000635 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000636 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000637 SkScalar w = devRect.width() - dx;
638 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000639 spare = GrMin(w, h);
640 }
641
642 if (spare <= 0) {
robertphillips@google.com18136d12013-05-10 11:05:58 +0000643 devRect.inset(-rx, -ry);
644 this->fillAARect(gpu, target, devRect, SkMatrix::I(), useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000645 return;
646 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000647
robertphillips@google.com42903302013-04-20 12:26:07 +0000648 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000649
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000650 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000651 if (!geo.succeeded()) {
652 GrPrintf("Failed to get space for vertices!\n");
653 return;
654 }
655 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
656 if (NULL == indexBuffer) {
657 GrPrintf("Failed to create index buffer!\n");
658 return;
659 }
660
661 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000662 size_t vsize = drawState->getVertexSize();
663 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000664
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000665 // We create vertices for four nested rectangles. There are two ramps from 0 to full
666 // coverage, one on the exterior of the stroke and the other on the interior.
667 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000668 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
669 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
670 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
671 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
672
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000673 set_inset_fan(fan0Pos, vsize, devRect,
674 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
675 set_inset_fan(fan1Pos, vsize, devRect,
676 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
677 set_inset_fan(fan2Pos, vsize, devRect,
678 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
679 set_inset_fan(fan3Pos, vsize, devRect,
680 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000681
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000682 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000683 verts += sizeof(GrPoint);
684 for (int i = 0; i < 4; ++i) {
685 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
686 }
687
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000688 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000689 GrColor innerColor;
690 if (useVertexCoverage) {
691 innerColor = 0xffffffff;
692 } else {
693 innerColor = target->getDrawState().getColor();
694 }
695 verts += 4 * vsize;
696 for (int i = 0; i < 8; ++i) {
697 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
698 }
699
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000700 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000701 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000702 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000703 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
704 }
705
706 target->setIndexSourceToBuffer(indexBuffer);
707 target->drawIndexed(kTriangles_GrPrimitiveType,
708 0, 0, 16, aaStrokeRectIndexCount());
709}