blob: 28dae2420fe4281dae24220e17671a9c85e01db5 [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);
223 }
224
225 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
226
227 GR_DECLARE_EFFECT_TEST;
228
229 typedef GrEffect INHERITED;
230};
231
232
233GR_DEFINE_EFFECT_TEST(GrRectEffect);
234
235GrEffectRef* GrRectEffect::TestCreate(SkMWCRandom* random,
236 GrContext* context,
237 const GrDrawTargetCaps&,
238 GrTexture* textures[]) {
239 return GrRectEffect::Create();
240}
241
242///////////////////////////////////////////////////////////////////////////////
243
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000244namespace {
245
robertphillips@google.com42903302013-04-20 12:26:07 +0000246extern const GrVertexAttrib gAARectCoverageAttribs[] = {
247 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
248 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
249};
250
251extern const GrVertexAttrib gAARectColorAttribs[] = {
252 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
253 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
254};
255
256static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
257 if (useCoverage) {
258 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
259 } else {
260 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
261 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000262}
263
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000264static void set_inset_fan(GrPoint* pts, size_t stride,
265 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000266 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
267 r.fRight - dx, r.fBottom - dy, stride);
268}
269
270};
271
272void GrAARectRenderer::reset() {
273 GrSafeSetNull(fAAFillRectIndexBuffer);
274 GrSafeSetNull(fAAStrokeRectIndexBuffer);
275}
276
robertphillips@google.com6d067302012-12-18 21:47:47 +0000277static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000278 0, 1, 5, 5, 4, 0,
279 1, 2, 6, 6, 5, 1,
280 2, 3, 7, 7, 6, 2,
281 3, 0, 4, 4, 7, 3,
282 4, 5, 6, 6, 7, 4,
283};
284
robertphillips@google.com6d067302012-12-18 21:47:47 +0000285static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
286static const int kVertsPerAAFillRect = 8;
287static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000288
289GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000290 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
291 sizeof(uint16_t) *
292 kNumAAFillRectsInIndexBuffer;
293
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000294 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000295 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000296 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +0000297 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
298 bool useTempData = (NULL == data);
299 if (useTempData) {
300 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
301 }
302 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
303 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
304 // the inner rect (for AA) and 2 for the inner rect.
305 int baseIdx = i * kIndicesPerAAFillRect;
306 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
307 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
308 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
309 }
310 }
311 if (useTempData) {
312 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
313 GrCrash("Can't get AA Fill Rect indices into buffer!");
314 }
315 SkDELETE_ARRAY(data);
316 } else {
317 fAAFillRectIndexBuffer->unlock();
318 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000319 }
320 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000321
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000322 return fAAFillRectIndexBuffer;
323}
324
robertphillips@google.com6d067302012-12-18 21:47:47 +0000325static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000326 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
327 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
328 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
329 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
330
331 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
332 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
333 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
334 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
335
336 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
337 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
338 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
339 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
340};
341
342int GrAARectRenderer::aaStrokeRectIndexCount() {
343 return GR_ARRAY_COUNT(gStrokeAARectIdx);
344}
345
346GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
347 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000348 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000349 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
350 if (NULL != fAAStrokeRectIndexBuffer) {
351#if GR_DEBUG
352 bool updated =
353#endif
354 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
355 sizeof(gStrokeAARectIdx));
356 GR_DEBUGASSERT(updated);
357 }
358 }
359 return fAAStrokeRectIndexBuffer;
360}
361
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000362void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
363 GrDrawTarget* target,
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000364 const GrRect& rect,
365 const SkMatrix& combinedMatrix,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000366 const GrRect& devRect,
367 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()) {
392 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
393 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
394 } else {
395 // compute transformed (1, 0) and (0, 1) vectors
396 SkVector vec[2] = {
397 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
398 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
399 };
400
401 vec[0].normalize();
402 vec[0].scale(SK_ScalarHalf);
403 vec[1].normalize();
404 vec[1].scale(SK_ScalarHalf);
405
406 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
407 rect.fRight, rect.fBottom, vsize);
408 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
409
410 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000411 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000412 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
413 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
414 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000415 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000416 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
417 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
418 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000419 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000420 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
421 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
422 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000423 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000424 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
425 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
426 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000427
428 verts += sizeof(GrPoint);
429 for (int i = 0; i < 4; ++i) {
430 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
431 }
432
433 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000434 if (useVertexCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000435 innerColor = 0xffffffff;
436 } else {
437 innerColor = target->getDrawState().getColor();
438 }
439
440 verts += 4 * vsize;
441 for (int i = 0; i < 4; ++i) {
442 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
443 }
444
445 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000446 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
447 kVertsPerAAFillRect,
448 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000449 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000450}
451
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000452namespace {
453
454// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000455struct RectVertex {
456 GrPoint fPos;
457 GrPoint fCenter;
458 GrPoint fDir;
459 GrPoint fWidthHeight;
460};
461
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000462// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000463extern const GrVertexAttrib gAARectVertexAttribs[] = {
464 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
465 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
466 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
467};
468
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000469// Axis Aligned
470struct AARectVertex {
471 GrPoint fPos;
472 GrPoint fOffset;
473 GrPoint fWidthHeight;
474};
475
476// Axis Aligned
477extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
478 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
479 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
480};
481
robertphillips@google.com42903302013-04-20 12:26:07 +0000482};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000483
484void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
485 GrDrawTarget* target,
486 const GrRect& rect,
487 const SkMatrix& combinedMatrix,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000488 const GrRect& devRect) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000489 GrDrawState* drawState = target->drawState();
490
491 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
492 combinedMatrix.mapPoints(&center, 1);
493
494 // compute transformed (0, 1) vector
495 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
496 dir.normalize();
497
498 // compute transformed (width, 0) and (0, height) vectors
499 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000500 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
501 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000502 };
503
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000504 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
505 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000506 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000507 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
508
509 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
510 if (!geo.succeeded()) {
511 GrPrintf("Failed to get space for vertices!\n");
512 return;
513 }
514
515 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
516
517 enum {
518 // the edge effects share this stage with glyph rendering
519 // (kGlyphMaskStage in GrTextContext) && SW path rendering
520 // (kPathMaskStage in GrSWMaskHelper)
521 kEdgeEffectStage = GrPaint::kTotalStages,
522 };
523
524 GrEffectRef* effect = GrRectEffect::Create();
525 static const int kRectAttrIndex = 1;
526 static const int kWidthIndex = 2;
527 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
528
529 for (int i = 0; i < 4; ++i) {
530 verts[i].fCenter = center;
531 verts[i].fDir = dir;
532 verts[i].fWidthHeight.fX = newWidth;
533 verts[i].fWidthHeight.fY = newHeight;
534 }
535
536 SkRect devBounds = {
537 devRect.fLeft - SK_ScalarHalf,
538 devRect.fTop - SK_ScalarHalf,
539 devRect.fRight + SK_ScalarHalf,
540 devRect.fBottom + SK_ScalarHalf
541 };
542
543 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
544 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
545 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
546 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
547
548 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
549 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
550 target->resetIndexSource();
551}
552
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000553void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
554 GrDrawTarget* target,
555 const GrRect& rect,
556 const SkMatrix& combinedMatrix,
557 const GrRect& devRect) {
558 GrDrawState* drawState = target->drawState();
559 SkASSERT(combinedMatrix.rectStaysRect());
560
561 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
562 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
563
564 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
565 if (!geo.succeeded()) {
566 GrPrintf("Failed to get space for vertices!\n");
567 return;
568 }
569
570 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
571
572 enum {
573 // the edge effects share this stage with glyph rendering
574 // (kGlyphMaskStage in GrTextContext) && SW path rendering
575 // (kPathMaskStage in GrSWMaskHelper)
576 kEdgeEffectStage = GrPaint::kTotalStages,
577 };
578
579 GrEffectRef* effect = GrAlignedRectEffect::Create();
580 static const int kOffsetIndex = 1;
581 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
582
583 SkRect devBounds = {
584 devRect.fLeft - SK_ScalarHalf,
585 devRect.fTop - SK_ScalarHalf,
586 devRect.fRight + SK_ScalarHalf,
587 devRect.fBottom + SK_ScalarHalf
588 };
589
590 GrPoint widthHeight = {
591 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
592 SkScalarHalf(devRect.height()) + SK_ScalarHalf
593 };
594
595 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
596 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
597 verts[0].fWidthHeight = widthHeight;
598
599 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
600 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
601 verts[1].fWidthHeight = widthHeight;
602
603 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
604 verts[2].fOffset = widthHeight;
605 verts[2].fWidthHeight = widthHeight;
606
607 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
608 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
609 verts[3].fWidthHeight = widthHeight;
610
611 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
612 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
613 target->resetIndexSource();
614}
615
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000616void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000617 GrDrawTarget* target,
618 const GrRect& devRect,
619 const GrVec& devStrokeSize,
620 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000621 GrDrawState* drawState = target->drawState();
622
bsalomon@google.com81712882012-11-01 17:12:34 +0000623 const SkScalar& dx = devStrokeSize.fX;
624 const SkScalar& dy = devStrokeSize.fY;
625 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
626 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000627
bsalomon@google.com81712882012-11-01 17:12:34 +0000628 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000629 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000630 SkScalar w = devRect.width() - dx;
631 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000632 spare = GrMin(w, h);
633 }
634
635 if (spare <= 0) {
636 GrRect r(devRect);
637 r.inset(-rx, -ry);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000638 this->fillAARect(gpu, target, r, SkMatrix::I(), r, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000639 return;
640 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000641
robertphillips@google.com42903302013-04-20 12:26:07 +0000642 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000643
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000644 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000645 if (!geo.succeeded()) {
646 GrPrintf("Failed to get space for vertices!\n");
647 return;
648 }
649 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
650 if (NULL == indexBuffer) {
651 GrPrintf("Failed to create index buffer!\n");
652 return;
653 }
654
655 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000656 size_t vsize = drawState->getVertexSize();
657 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000658
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000659 // We create vertices for four nested rectangles. There are two ramps from 0 to full
660 // coverage, one on the exterior of the stroke and the other on the interior.
661 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000662 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
663 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
664 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
665 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
666
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000667 set_inset_fan(fan0Pos, vsize, devRect,
668 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
669 set_inset_fan(fan1Pos, vsize, devRect,
670 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
671 set_inset_fan(fan2Pos, vsize, devRect,
672 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
673 set_inset_fan(fan3Pos, vsize, devRect,
674 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000675
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000676 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000677 verts += sizeof(GrPoint);
678 for (int i = 0; i < 4; ++i) {
679 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
680 }
681
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000682 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000683 GrColor innerColor;
684 if (useVertexCoverage) {
685 innerColor = 0xffffffff;
686 } else {
687 innerColor = target->getDrawState().getColor();
688 }
689 verts += 4 * vsize;
690 for (int i = 0; i < 8; ++i) {
691 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
692 }
693
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000694 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000695 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000696 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000697 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
698 }
699
700 target->setIndexSourceToBuffer(indexBuffer);
701 target->drawIndexed(kTriangles_GrPrimitiveType,
702 0, 0, 16, aaStrokeRectIndexCount());
703}