blob: 0b593b9a5f39729f4a5be96d083d16485bf56944 [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 const GrRect& devRect,
368 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000369 GrDrawState* drawState = target->drawState();
370
robertphillips@google.com42903302013-04-20 12:26:07 +0000371 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000372
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000373 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000374 if (!geo.succeeded()) {
375 GrPrintf("Failed to get space for vertices!\n");
376 return;
377 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000378
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000379 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
380 if (NULL == indexBuffer) {
381 GrPrintf("Failed to create index buffer!\n");
382 return;
383 }
384
385 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000386 size_t vsize = drawState->getVertexSize();
387 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000388
389 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
390 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
391
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000392 if (combinedMatrix.rectStaysRect()) {
393 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
394 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
395 } else {
396 // compute transformed (1, 0) and (0, 1) vectors
397 SkVector vec[2] = {
398 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
399 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
400 };
401
402 vec[0].normalize();
403 vec[0].scale(SK_ScalarHalf);
404 vec[1].normalize();
405 vec[1].scale(SK_ScalarHalf);
406
407 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
408 rect.fRight, rect.fBottom, vsize);
409 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
410
411 // TL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000412 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000413 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
414 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
415 // BL
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000416 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000417 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
418 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
419 // BR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000420 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000421 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
422 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
423 // TR
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000424 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000425 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
426 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
427 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000428
429 verts += sizeof(GrPoint);
430 for (int i = 0; i < 4; ++i) {
431 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
432 }
433
434 GrColor innerColor;
skia.committer@gmail.com2fd42c42013-05-03 07:01:00 +0000435 if (useVertexCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000436 innerColor = 0xffffffff;
437 } else {
438 innerColor = target->getDrawState().getColor();
439 }
440
441 verts += 4 * vsize;
442 for (int i = 0; i < 4; ++i) {
443 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
444 }
445
446 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000447 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
448 kVertsPerAAFillRect,
449 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000450 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000451}
452
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000453namespace {
454
455// Rotated
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000456struct RectVertex {
457 GrPoint fPos;
458 GrPoint fCenter;
459 GrPoint fDir;
460 GrPoint fWidthHeight;
461};
462
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000463// Rotated
robertphillips@google.com42903302013-04-20 12:26:07 +0000464extern const GrVertexAttrib gAARectVertexAttribs[] = {
465 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
466 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
467 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
468};
469
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000470// Axis Aligned
471struct AARectVertex {
472 GrPoint fPos;
473 GrPoint fOffset;
474 GrPoint fWidthHeight;
475};
476
477// Axis Aligned
478extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
479 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
480 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
481};
482
robertphillips@google.com42903302013-04-20 12:26:07 +0000483};
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000484
485void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
486 GrDrawTarget* target,
487 const GrRect& rect,
488 const SkMatrix& combinedMatrix,
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000489 const GrRect& devRect) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000490 GrDrawState* drawState = target->drawState();
491
492 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
493 combinedMatrix.mapPoints(&center, 1);
494
495 // compute transformed (0, 1) vector
496 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
497 dir.normalize();
498
499 // compute transformed (width, 0) and (0, height) vectors
500 SkVector vec[2] = {
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000501 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
502 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000503 };
504
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000505 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
506 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
robertphillips@google.com42903302013-04-20 12:26:07 +0000507 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000508 GrAssert(sizeof(RectVertex) == drawState->getVertexSize());
509
510 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
511 if (!geo.succeeded()) {
512 GrPrintf("Failed to get space for vertices!\n");
513 return;
514 }
515
516 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
517
518 enum {
519 // the edge effects share this stage with glyph rendering
520 // (kGlyphMaskStage in GrTextContext) && SW path rendering
521 // (kPathMaskStage in GrSWMaskHelper)
522 kEdgeEffectStage = GrPaint::kTotalStages,
523 };
524
525 GrEffectRef* effect = GrRectEffect::Create();
526 static const int kRectAttrIndex = 1;
527 static const int kWidthIndex = 2;
528 drawState->setEffect(kEdgeEffectStage, effect, kRectAttrIndex, kWidthIndex)->unref();
529
530 for (int i = 0; i < 4; ++i) {
531 verts[i].fCenter = center;
532 verts[i].fDir = dir;
533 verts[i].fWidthHeight.fX = newWidth;
534 verts[i].fWidthHeight.fY = newHeight;
535 }
536
537 SkRect devBounds = {
538 devRect.fLeft - SK_ScalarHalf,
539 devRect.fTop - SK_ScalarHalf,
540 devRect.fRight + SK_ScalarHalf,
541 devRect.fBottom + SK_ScalarHalf
542 };
543
544 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
545 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
546 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
547 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
548
549 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
550 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
551 target->resetIndexSource();
552}
553
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000554void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
555 GrDrawTarget* target,
556 const GrRect& rect,
557 const SkMatrix& combinedMatrix,
558 const GrRect& devRect) {
559 GrDrawState* drawState = target->drawState();
560 SkASSERT(combinedMatrix.rectStaysRect());
561
562 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
563 GrAssert(sizeof(AARectVertex) == drawState->getVertexSize());
564
565 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
566 if (!geo.succeeded()) {
567 GrPrintf("Failed to get space for vertices!\n");
568 return;
569 }
570
571 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
572
573 enum {
574 // the edge effects share this stage with glyph rendering
575 // (kGlyphMaskStage in GrTextContext) && SW path rendering
576 // (kPathMaskStage in GrSWMaskHelper)
577 kEdgeEffectStage = GrPaint::kTotalStages,
578 };
579
580 GrEffectRef* effect = GrAlignedRectEffect::Create();
581 static const int kOffsetIndex = 1;
582 drawState->setEffect(kEdgeEffectStage, effect, kOffsetIndex)->unref();
583
584 SkRect devBounds = {
585 devRect.fLeft - SK_ScalarHalf,
586 devRect.fTop - SK_ScalarHalf,
587 devRect.fRight + SK_ScalarHalf,
588 devRect.fBottom + SK_ScalarHalf
589 };
590
591 GrPoint widthHeight = {
592 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
593 SkScalarHalf(devRect.height()) + SK_ScalarHalf
594 };
595
596 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
597 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
598 verts[0].fWidthHeight = widthHeight;
599
600 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
601 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
602 verts[1].fWidthHeight = widthHeight;
603
604 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
605 verts[2].fOffset = widthHeight;
606 verts[2].fWidthHeight = widthHeight;
607
608 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
609 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
610 verts[3].fWidthHeight = widthHeight;
611
612 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
613 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
614 target->resetIndexSource();
615}
616
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000617void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000618 GrDrawTarget* target,
619 const GrRect& devRect,
620 const GrVec& devStrokeSize,
621 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000622 GrDrawState* drawState = target->drawState();
623
bsalomon@google.com81712882012-11-01 17:12:34 +0000624 const SkScalar& dx = devStrokeSize.fX;
625 const SkScalar& dy = devStrokeSize.fY;
626 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
627 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000628
bsalomon@google.com81712882012-11-01 17:12:34 +0000629 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000630 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000631 SkScalar w = devRect.width() - dx;
632 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000633 spare = GrMin(w, h);
634 }
635
636 if (spare <= 0) {
637 GrRect r(devRect);
638 r.inset(-rx, -ry);
robertphillips@google.comb19cb7f2013-05-02 15:37:20 +0000639 this->fillAARect(gpu, target, r, SkMatrix::I(), r, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000640 return;
641 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000642
robertphillips@google.com42903302013-04-20 12:26:07 +0000643 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000644
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000645 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000646 if (!geo.succeeded()) {
647 GrPrintf("Failed to get space for vertices!\n");
648 return;
649 }
650 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
651 if (NULL == indexBuffer) {
652 GrPrintf("Failed to create index buffer!\n");
653 return;
654 }
655
656 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000657 size_t vsize = drawState->getVertexSize();
658 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000659
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000660 // We create vertices for four nested rectangles. There are two ramps from 0 to full
661 // coverage, one on the exterior of the stroke and the other on the interior.
662 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000663 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
664 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
665 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
666 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
667
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000668 set_inset_fan(fan0Pos, vsize, devRect,
669 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
670 set_inset_fan(fan1Pos, vsize, devRect,
671 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
672 set_inset_fan(fan2Pos, vsize, devRect,
673 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
674 set_inset_fan(fan3Pos, vsize, devRect,
675 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000676
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000677 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000678 verts += sizeof(GrPoint);
679 for (int i = 0; i < 4; ++i) {
680 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
681 }
682
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000683 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000684 GrColor innerColor;
685 if (useVertexCoverage) {
686 innerColor = 0xffffffff;
687 } else {
688 innerColor = target->getDrawState().getColor();
689 }
690 verts += 4 * vsize;
691 for (int i = 0; i < 8; ++i) {
692 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
693 }
694
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000695 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000696 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000697 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000698 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
699 }
700
701 target->setIndexSourceToBuffer(indexBuffer);
702 target->drawIndexed(kTriangles_GrPrimitiveType,
703 0, 0, 16, aaStrokeRectIndexCount());
704}