blob: 5acb4068a1790ff87c2a9caf84b48c237d05f902 [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,
364 const GrRect& devRect,
365 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000366 GrDrawState* drawState = target->drawState();
367
robertphillips@google.com42903302013-04-20 12:26:07 +0000368 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000369
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000370 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000371 if (!geo.succeeded()) {
372 GrPrintf("Failed to get space for vertices!\n");
373 return;
374 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000375
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000376 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
377 if (NULL == indexBuffer) {
378 GrPrintf("Failed to create index buffer!\n");
379 return;
380 }
381
382 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000383 size_t vsize = drawState->getVertexSize();
384 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000385
386 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
387 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
388
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000389 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
390 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000391
392 verts += sizeof(GrPoint);
393 for (int i = 0; i < 4; ++i) {
394 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
395 }
396
397 GrColor innerColor;
398 if (useVertexCoverage) {
399 innerColor = 0xffffffff;
400 } else {
401 innerColor = target->getDrawState().getColor();
402 }
403
404 verts += 4 * vsize;
405 for (int i = 0; i < 4; ++i) {
406 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
407 }
408
409 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000410 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
411 kVertsPerAAFillRect,
412 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000413 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000414}
415
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000416namespace {
417
418// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000419struct RectVertex {
420 GrPoint fPos;
421 GrPoint fCenter;
422 GrPoint fDir;
423 GrPoint fWidthHeight;
424};
425
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000426// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000427extern const GrVertexAttrib gAARectVertexAttribs[] = {
428 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
429 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
430 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
431};
432
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000433// Axis Aligned
434struct AARectVertex {
435 GrPoint fPos;
436 GrPoint fOffset;
437 GrPoint fWidthHeight;
438};
439
440// Axis Aligned
441extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
442 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
443 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
444};
445
robertphillips@google.com42903302013-04-20 12:26:07 +0000446};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000447
448void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
449 GrDrawTarget* target,
450 const GrRect& rect,
451 const SkMatrix& combinedMatrix,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000452 const GrRect& devRect) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000453 GrDrawState* drawState = target->drawState();
454
455 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
456 combinedMatrix.mapPoints(&center, 1);
457
458 // compute transformed (0, 1) vector
459 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
460 dir.normalize();
461
462 // compute transformed (width, 0) and (0, height) vectors
463 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000464 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
465 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000466 };
467
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000468 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
469 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000470 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000471 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
472
473 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
474 if (!geo.succeeded()) {
475 GrPrintf("Failed to get space for vertices!\n");
476 return;
477 }
478
479 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
480
481 enum {
482 // the edge effects share this stage with glyph rendering
483 // (kGlyphMaskStage in GrTextContext) && SW path rendering
484 // (kPathMaskStage in GrSWMaskHelper)
485 kEdgeEffectStage = GrPaint::kTotalStages,
486 };
487
488 GrEffectRef* effect = GrRectEffect::Create();
489 static const int kRectAttrIndex = 1;
490 static const int kWidthIndex = 2;
491 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
492
493 for (int i = 0; i < 4; ++i) {
494 verts[i].fCenter = center;
495 verts[i].fDir = dir;
496 verts[i].fWidthHeight.fX = newWidth;
497 verts[i].fWidthHeight.fY = newHeight;
498 }
499
500 SkRect devBounds = {
501 devRect.fLeft - SK_ScalarHalf,
502 devRect.fTop - SK_ScalarHalf,
503 devRect.fRight + SK_ScalarHalf,
504 devRect.fBottom + SK_ScalarHalf
505 };
506
507 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
508 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
509 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
510 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
511
512 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
513 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
514 target->resetIndexSource();
515}
516
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000517void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
518 GrDrawTarget* target,
519 const GrRect& rect,
520 const SkMatrix& combinedMatrix,
521 const GrRect& devRect) {
522 GrDrawState* drawState = target->drawState();
523 SkASSERT(combinedMatrix.rectStaysRect());
524
525 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
526 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
527
528 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
529 if (!geo.succeeded()) {
530 GrPrintf("Failed to get space for vertices!\n");
531 return;
532 }
533
534 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
535
536 enum {
537 // the edge effects share this stage with glyph rendering
538 // (kGlyphMaskStage in GrTextContext) && SW path rendering
539 // (kPathMaskStage in GrSWMaskHelper)
540 kEdgeEffectStage = GrPaint::kTotalStages,
541 };
542
543 GrEffectRef* effect = GrAlignedRectEffect::Create();
544 static const int kOffsetIndex = 1;
545 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
546
547 SkRect devBounds = {
548 devRect.fLeft - SK_ScalarHalf,
549 devRect.fTop - SK_ScalarHalf,
550 devRect.fRight + SK_ScalarHalf,
551 devRect.fBottom + SK_ScalarHalf
552 };
553
554 GrPoint widthHeight = {
555 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
556 SkScalarHalf(devRect.height()) + SK_ScalarHalf
557 };
558
559 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
560 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
561 verts[0].fWidthHeight = widthHeight;
562
563 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
564 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
565 verts[1].fWidthHeight = widthHeight;
566
567 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
568 verts[2].fOffset = widthHeight;
569 verts[2].fWidthHeight = widthHeight;
570
571 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
572 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
573 verts[3].fWidthHeight = widthHeight;
574
575 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
576 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
577 target->resetIndexSource();
578}
579
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000580void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000581 GrDrawTarget* target,
582 const GrRect& devRect,
583 const GrVec& devStrokeSize,
584 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000585 GrDrawState* drawState = target->drawState();
586
bsalomon@google.com81712882012-11-01 17:12:34 +0000587 const SkScalar& dx = devStrokeSize.fX;
588 const SkScalar& dy = devStrokeSize.fY;
589 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
590 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000591
bsalomon@google.com81712882012-11-01 17:12:34 +0000592 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000593 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000594 SkScalar w = devRect.width() - dx;
595 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000596 spare = GrMin(w, h);
597 }
598
599 if (spare <= 0) {
600 GrRect r(devRect);
601 r.inset(-rx, -ry);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000602 this->fillAARect(gpu, target, r, SkMatrix::I(), r, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000603 return;
604 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000605
robertphillips@google.com42903302013-04-20 12:26:07 +0000606 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000607
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000608 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000609 if (!geo.succeeded()) {
610 GrPrintf("Failed to get space for vertices!\n");
611 return;
612 }
613 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
614 if (NULL == indexBuffer) {
615 GrPrintf("Failed to create index buffer!\n");
616 return;
617 }
618
619 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000620 size_t vsize = drawState->getVertexSize();
621 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000622
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000623 // We create vertices for four nested rectangles. There are two ramps from 0 to full
624 // coverage, one on the exterior of the stroke and the other on the interior.
625 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000626 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
627 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
628 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
629 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
630
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000631 set_inset_fan(fan0Pos, vsize, devRect,
632 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
633 set_inset_fan(fan1Pos, vsize, devRect,
634 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
635 set_inset_fan(fan2Pos, vsize, devRect,
636 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
637 set_inset_fan(fan3Pos, vsize, devRect,
638 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000639
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000640 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000641 verts += sizeof(GrPoint);
642 for (int i = 0; i < 4; ++i) {
643 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
644 }
645
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000646 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000647 GrColor innerColor;
648 if (useVertexCoverage) {
649 innerColor = 0xffffffff;
650 } else {
651 innerColor = target->getDrawState().getColor();
652 }
653 verts += 4 * vsize;
654 for (int i = 0; i < 8; ++i) {
655 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
656 }
657
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000658 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000659 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000660 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000661 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
662 }
663
664 target->setIndexSourceToBuffer(indexBuffer);
665 target->drawIndexed(kTriangles_GrPrimitiveType,
666 0, 0, 16, aaStrokeRectIndexCount());
667}