blob: f9ed13f87216592744673d438cd8bf5bf8b45b91 [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.com4b140b52013-05-02 17:13:13 +0000391 if (combinedMatrix.rectStaysRect()) {
robertphillips@google.com91b71162013-05-10 14:09:54 +0000392 SkRect devRect;
393 combinedMatrix.mapRect(&devRect, rect);
394
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000395 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
robertphillips@google.com91b71162013-05-10 14:09:54 +0000409 // create the rotated rect
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000410 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
411 rect.fRight, rect.fBottom, vsize);
412 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
413
robertphillips@google.com91b71162013-05-10 14:09:54 +0000414 // Now create the inset points and then outset the original
415 // rotated points
416
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000417 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000418 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000419 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
420 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
421 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000422 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000423 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
424 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
425 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000426 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000427 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
428 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
429 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000430 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000431 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
432 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
433 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000434
435 verts += sizeof(GrPoint);
436 for (int i = 0; i < 4; ++i) {
437 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
438 }
439
440 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000441 if (useVertexCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000442 innerColor = 0xffffffff;
443 } else {
444 innerColor = target->getDrawState().getColor();
445 }
446
447 verts += 4 * vsize;
448 for (int i = 0; i < 4; ++i) {
449 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
450 }
451
452 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000453 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
454 kVertsPerAAFillRect,
455 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000456 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000457}
458
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000459namespace {
460
461// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000462struct RectVertex {
463 GrPoint fPos;
464 GrPoint fCenter;
465 GrPoint fDir;
466 GrPoint fWidthHeight;
467};
468
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000469// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000470extern const GrVertexAttrib gAARectVertexAttribs[] = {
471 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
472 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
473 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
474};
475
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000476// Axis Aligned
477struct AARectVertex {
478 GrPoint fPos;
479 GrPoint fOffset;
480 GrPoint fWidthHeight;
481};
482
483// Axis Aligned
484extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
485 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
486 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
487};
488
robertphillips@google.com42903302013-04-20 12:26:07 +0000489};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000490
491void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
492 GrDrawTarget* target,
493 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000494 const SkMatrix& combinedMatrix) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000495 GrDrawState* drawState = target->drawState();
496
497 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
498 combinedMatrix.mapPoints(&center, 1);
499
500 // compute transformed (0, 1) vector
501 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
502 dir.normalize();
503
504 // compute transformed (width, 0) and (0, height) vectors
505 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000506 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
507 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000508 };
509
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000510 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
511 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000512 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000513 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
514
515 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
516 if (!geo.succeeded()) {
517 GrPrintf("Failed to get space for vertices!\n");
518 return;
519 }
520
521 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
522
523 enum {
524 // the edge effects share this stage with glyph rendering
525 // (kGlyphMaskStage in GrTextContext) && SW path rendering
526 // (kPathMaskStage in GrSWMaskHelper)
527 kEdgeEffectStage = GrPaint::kTotalStages,
528 };
529
530 GrEffectRef* effect = GrRectEffect::Create();
531 static const int kRectAttrIndex = 1;
532 static const int kWidthIndex = 2;
533 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
534
535 for (int i = 0; i < 4; ++i) {
536 verts[i].fCenter = center;
537 verts[i].fDir = dir;
538 verts[i].fWidthHeight.fX = newWidth;
539 verts[i].fWidthHeight.fY = newHeight;
540 }
541
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000542 SkRect devRect;
543 combinedMatrix.mapRect(&devRect, rect);
544
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000545 SkRect devBounds = {
546 devRect.fLeft - SK_ScalarHalf,
547 devRect.fTop - SK_ScalarHalf,
548 devRect.fRight + SK_ScalarHalf,
549 devRect.fBottom + SK_ScalarHalf
550 };
551
552 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
553 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
554 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
555 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
556
557 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
558 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
559 target->resetIndexSource();
560}
561
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000562void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
563 GrDrawTarget* target,
564 const GrRect& rect,
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000565 const SkMatrix& combinedMatrix) {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000566 GrDrawState* drawState = target->drawState();
567 SkASSERT(combinedMatrix.rectStaysRect());
568
569 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
570 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
571
572 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
573 if (!geo.succeeded()) {
574 GrPrintf("Failed to get space for vertices!\n");
575 return;
576 }
577
578 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
579
580 enum {
581 // the edge effects share this stage with glyph rendering
582 // (kGlyphMaskStage in GrTextContext) && SW path rendering
583 // (kPathMaskStage in GrSWMaskHelper)
584 kEdgeEffectStage = GrPaint::kTotalStages,
585 };
586
587 GrEffectRef* effect = GrAlignedRectEffect::Create();
588 static const int kOffsetIndex = 1;
589 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
590
robertphillips@google.com114eb9e2013-05-10 13:16:13 +0000591 SkRect devRect;
592 combinedMatrix.mapRect(&devRect, rect);
593
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000594 SkRect devBounds = {
595 devRect.fLeft - SK_ScalarHalf,
596 devRect.fTop - SK_ScalarHalf,
597 devRect.fRight + SK_ScalarHalf,
598 devRect.fBottom + SK_ScalarHalf
599 };
600
601 GrPoint widthHeight = {
602 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
603 SkScalarHalf(devRect.height()) + SK_ScalarHalf
604 };
605
606 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
607 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
608 verts[0].fWidthHeight = widthHeight;
609
610 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
611 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
612 verts[1].fWidthHeight = widthHeight;
613
614 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
615 verts[2].fOffset = widthHeight;
616 verts[2].fWidthHeight = widthHeight;
617
618 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
619 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
620 verts[3].fWidthHeight = widthHeight;
621
622 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
623 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
624 target->resetIndexSource();
625}
626
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000627void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000628 GrDrawTarget* target,
robertphillips@google.com18136d12013-05-10 11:05:58 +0000629 const GrRect& rect,
630 const SkMatrix& combinedMatrix,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000631 const GrVec& devStrokeSize,
632 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000633 GrDrawState* drawState = target->drawState();
634
robertphillips@google.com18136d12013-05-10 11:05:58 +0000635 const SkScalar dx = devStrokeSize.fX;
636 const SkScalar dy = devStrokeSize.fY;
bsalomon@google.com81712882012-11-01 17:12:34 +0000637 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
638 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000639
robertphillips@google.com18136d12013-05-10 11:05:58 +0000640 SkRect devRect;
641 combinedMatrix.mapRect(&devRect, rect);
642
bsalomon@google.com81712882012-11-01 17:12:34 +0000643 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000644 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000645 SkScalar w = devRect.width() - dx;
646 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000647 spare = GrMin(w, h);
648 }
649
650 if (spare <= 0) {
robertphillips@google.com18136d12013-05-10 11:05:58 +0000651 devRect.inset(-rx, -ry);
652 this->fillAARect(gpu, target, devRect, SkMatrix::I(), useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000653 return;
654 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000655
robertphillips@google.com42903302013-04-20 12:26:07 +0000656 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000657
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000658 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000659 if (!geo.succeeded()) {
660 GrPrintf("Failed to get space for vertices!\n");
661 return;
662 }
663 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
664 if (NULL == indexBuffer) {
665 GrPrintf("Failed to create index buffer!\n");
666 return;
667 }
668
669 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000670 size_t vsize = drawState->getVertexSize();
671 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000672
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000673 // We create vertices for four nested rectangles. There are two ramps from 0 to full
674 // coverage, one on the exterior of the stroke and the other on the interior.
675 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000676 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
677 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
678 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
679 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
680
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000681 set_inset_fan(fan0Pos, vsize, devRect,
682 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
683 set_inset_fan(fan1Pos, vsize, devRect,
684 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
685 set_inset_fan(fan2Pos, vsize, devRect,
686 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
687 set_inset_fan(fan3Pos, vsize, devRect,
688 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000689
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000690 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000691 verts += sizeof(GrPoint);
692 for (int i = 0; i < 4; ++i) {
693 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
694 }
695
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000696 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000697 GrColor innerColor;
698 if (useVertexCoverage) {
699 innerColor = 0xffffffff;
700 } else {
701 innerColor = target->getDrawState().getColor();
702 }
703 verts += 4 * vsize;
704 for (int i = 0; i < 8; ++i) {
705 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
706 }
707
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000708 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000709 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000710 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000711 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
712 }
713
714 target->setIndexSourceToBuffer(indexBuffer);
715 target->drawIndexed(kTriangles_GrPrimitiveType,
716 0, 0, 16, aaStrokeRectIndexCount());
717}