1 /*
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 "GrGpu.h"
10 #include "gl/GrGLEffect.h"
11 #include "gl/GrGLVertexEffect.h"
12 #include "GrTBackendEffectFactory.h"
13 #include "SkColorPriv.h"
14 #include "effects/GrVertexEffect.h"
15
16 ///////////////////////////////////////////////////////////////////////////////
17 class GrGLAlignedRectEffect;
18
19 // Axis Aligned special case
20 class GrAlignedRectEffect : public GrVertexEffect {
21 public:
Create()22 static GrEffectRef* Create() {
23 GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
24 gAlignedRectEffect->ref();
25 return gAlignedRectEffect;
26 }
27
~GrAlignedRectEffect()28 virtual ~GrAlignedRectEffect() {}
29
Name()30 static const char* Name() { return "AlignedRectEdge"; }
31
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const32 virtual void getConstantColorComponents(GrColor* color,
33 uint32_t* validFlags) const SK_OVERRIDE {
34 *validFlags = 0;
35 }
36
getFactory() const37 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
38 return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
39 }
40
41 class GLEffect : public GrGLVertexEffect {
42 public:
GLEffect(const GrBackendEffectFactory & factory,const GrDrawEffect &)43 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
44 : INHERITED (factory) {}
45
emitCode(GrGLFullShaderBuilder * builder,const GrDrawEffect & drawEffect,EffectKey key,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)46 virtual void emitCode(GrGLFullShaderBuilder* builder,
47 const GrDrawEffect& drawEffect,
48 EffectKey key,
49 const char* outputColor,
50 const char* inputColor,
51 const TransformedCoordsArray&,
52 const TextureSamplerArray& samplers) SK_OVERRIDE {
53 // setup the varying for the Axis aligned rect effect
54 // xy -> interpolated offset
55 // zw -> w/2+0.5, h/2+0.5
56 const char *vsRectName, *fsRectName;
57 builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
58 const SkString* attr0Name =
59 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
60 builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
61
62 // TODO: compute all these offsets, spans, and scales in the VS
63 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
64 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
65 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
66 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
67 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
68 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
69 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
70 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
71 // value of coverage that is used. In other words it is the coverage that is
72 // used in the interior of the rect after the ramp.
73 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
74 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
75
76 // Compute the coverage for the rect's width
77 builder->fsCodeAppendf(
78 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
79 fsRectName);
80 // Compute the coverage for the rect's height and merge with the width
81 builder->fsCodeAppendf(
82 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
83 fsRectName, fsRectName);
84
85
86 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
87 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
88 }
89
GenKey(const GrDrawEffect & drawEffect,const GrGLCaps &)90 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
91 return 0;
92 }
93
setData(const GrGLUniformManager & uman,const GrDrawEffect &)94 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
95
96 private:
97 typedef GrGLVertexEffect INHERITED;
98 };
99
100
101 private:
GrAlignedRectEffect()102 GrAlignedRectEffect() : GrVertexEffect() {
103 this->addVertexAttrib(kVec4f_GrSLType);
104 }
105
onIsEqual(const GrEffect &) const106 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
107
108 GR_DECLARE_EFFECT_TEST;
109
110 typedef GrVertexEffect INHERITED;
111 };
112
113
114 GR_DEFINE_EFFECT_TEST(GrAlignedRectEffect);
115
TestCreate(SkRandom * random,GrContext * context,const GrDrawTargetCaps &,GrTexture * textures[])116 GrEffectRef* GrAlignedRectEffect::TestCreate(SkRandom* random,
117 GrContext* context,
118 const GrDrawTargetCaps&,
119 GrTexture* textures[]) {
120 return GrAlignedRectEffect::Create();
121 }
122
123 ///////////////////////////////////////////////////////////////////////////////
124 class GrGLRectEffect;
125
126 /**
127 * The output of this effect is a modulation of the input color and coverage
128 * for an arbitrarily oriented rect. The rect is specified as:
129 * Center of the rect
130 * Unit vector point down the height of the rect
131 * Half width + 0.5
132 * Half height + 0.5
133 * The center and vector are stored in a vec4 varying ("RectEdge") with the
134 * center in the xy components and the vector in the zw components.
135 * The munged width and height are stored in a vec2 varying ("WidthHeight")
136 * with the width in x and the height in y.
137 */
138 class GrRectEffect : public GrVertexEffect {
139 public:
Create()140 static GrEffectRef* Create() {
141 GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
142 gRectEffect->ref();
143 return gRectEffect;
144 }
145
~GrRectEffect()146 virtual ~GrRectEffect() {}
147
Name()148 static const char* Name() { return "RectEdge"; }
149
getConstantColorComponents(GrColor * color,uint32_t * validFlags) const150 virtual void getConstantColorComponents(GrColor* color,
151 uint32_t* validFlags) const SK_OVERRIDE {
152 *validFlags = 0;
153 }
154
getFactory() const155 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
156 return GrTBackendEffectFactory<GrRectEffect>::getInstance();
157 }
158
159 class GLEffect : public GrGLVertexEffect {
160 public:
GLEffect(const GrBackendEffectFactory & factory,const GrDrawEffect &)161 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
162 : INHERITED (factory) {}
163
emitCode(GrGLFullShaderBuilder * builder,const GrDrawEffect & drawEffect,EffectKey key,const char * outputColor,const char * inputColor,const TransformedCoordsArray &,const TextureSamplerArray & samplers)164 virtual void emitCode(GrGLFullShaderBuilder* builder,
165 const GrDrawEffect& drawEffect,
166 EffectKey key,
167 const char* outputColor,
168 const char* inputColor,
169 const TransformedCoordsArray&,
170 const TextureSamplerArray& samplers) SK_OVERRIDE {
171 // setup the varying for the center point and the unit vector
172 // that points down the height of the rect
173 const char *vsRectEdgeName, *fsRectEdgeName;
174 builder->addVarying(kVec4f_GrSLType, "RectEdge",
175 &vsRectEdgeName, &fsRectEdgeName);
176 const SkString* attr0Name =
177 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
178 builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
179
180 // setup the varying for width/2+.5 and height/2+.5
181 const char *vsWidthHeightName, *fsWidthHeightName;
182 builder->addVarying(kVec2f_GrSLType, "WidthHeight",
183 &vsWidthHeightName, &fsWidthHeightName);
184 const SkString* attr1Name =
185 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
186 builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
187
188 // TODO: compute all these offsets, spans, and scales in the VS
189 builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
190 builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
191 builder->fsCodeAppend("\tfloat outset = 0.5;\n");
192 // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
193 // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
194 builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
195 builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
196 // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
197 // value of coverage that is used. In other words it is the coverage that is
198 // used in the interior of the rect after the ramp.
199 builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
200 builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
201
202 // Compute the coverage for the rect's width
203 builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
204 builder->fragmentPosition(), fsRectEdgeName);
205 builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
206 fsRectEdgeName, fsRectEdgeName);
207 builder->fsCodeAppendf(
208 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
209 fsWidthHeightName);
210
211 // Compute the coverage for the rect's height and merge with the width
212 builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
213 fsRectEdgeName);
214 builder->fsCodeAppendf(
215 "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
216 fsWidthHeightName);
217
218
219 builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
220 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
221 }
222
GenKey(const GrDrawEffect & drawEffect,const GrGLCaps &)223 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
224 return 0;
225 }
226
setData(const GrGLUniformManager & uman,const GrDrawEffect &)227 virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
228
229 private:
230 typedef GrGLVertexEffect INHERITED;
231 };
232
233
234 private:
GrRectEffect()235 GrRectEffect() : GrVertexEffect() {
236 this->addVertexAttrib(kVec4f_GrSLType);
237 this->addVertexAttrib(kVec2f_GrSLType);
238 this->setWillReadFragmentPosition();
239 }
240
onIsEqual(const GrEffect &) const241 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
242
243 GR_DECLARE_EFFECT_TEST;
244
245 typedef GrVertexEffect INHERITED;
246 };
247
248
249 GR_DEFINE_EFFECT_TEST(GrRectEffect);
250
TestCreate(SkRandom * random,GrContext * context,const GrDrawTargetCaps &,GrTexture * textures[])251 GrEffectRef* GrRectEffect::TestCreate(SkRandom* random,
252 GrContext* context,
253 const GrDrawTargetCaps&,
254 GrTexture* textures[]) {
255 return GrRectEffect::Create();
256 }
257
258 ///////////////////////////////////////////////////////////////////////////////
259
260 namespace {
261
262 extern const GrVertexAttrib gAARectCoverageAttribs[] = {
263 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
264 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
265 };
266
267 extern const GrVertexAttrib gAARectColorAttribs[] = {
268 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
269 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
270 };
271
set_aa_rect_vertex_attributes(GrDrawState * drawState,bool useCoverage)272 static void set_aa_rect_vertex_attributes(GrDrawState* drawState, bool useCoverage) {
273 if (useCoverage) {
274 drawState->setVertexAttribs<gAARectCoverageAttribs>(SK_ARRAY_COUNT(gAARectCoverageAttribs));
275 } else {
276 drawState->setVertexAttribs<gAARectColorAttribs>(SK_ARRAY_COUNT(gAARectColorAttribs));
277 }
278 }
279
set_inset_fan(GrPoint * pts,size_t stride,const SkRect & r,SkScalar dx,SkScalar dy)280 static void set_inset_fan(GrPoint* pts, size_t stride,
281 const SkRect& r, SkScalar dx, SkScalar dy) {
282 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
283 r.fRight - dx, r.fBottom - dy, stride);
284 }
285
286 };
287
reset()288 void GrAARectRenderer::reset() {
289 SkSafeSetNull(fAAFillRectIndexBuffer);
290 SkSafeSetNull(fAAMiterStrokeRectIndexBuffer);
291 SkSafeSetNull(fAABevelStrokeRectIndexBuffer);
292 }
293
294 static const uint16_t gFillAARectIdx[] = {
295 0, 1, 5, 5, 4, 0,
296 1, 2, 6, 6, 5, 1,
297 2, 3, 7, 7, 6, 2,
298 3, 0, 4, 4, 7, 3,
299 4, 5, 6, 6, 7, 4,
300 };
301
302 static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
303 static const int kVertsPerAAFillRect = 8;
304 static const int kNumAAFillRectsInIndexBuffer = 256;
305
aaFillRectIndexBuffer(GrGpu * gpu)306 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
307 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
308 sizeof(uint16_t) *
309 kNumAAFillRectsInIndexBuffer;
310
311 if (NULL == fAAFillRectIndexBuffer) {
312 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
313 if (NULL != fAAFillRectIndexBuffer) {
314 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
315 bool useTempData = (NULL == data);
316 if (useTempData) {
317 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
318 }
319 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
320 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
321 // the inner rect (for AA) and 2 for the inner rect.
322 int baseIdx = i * kIndicesPerAAFillRect;
323 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
324 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
325 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
326 }
327 }
328 if (useTempData) {
329 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
330 GrCrash("Can't get AA Fill Rect indices into buffer!");
331 }
332 SkDELETE_ARRAY(data);
333 } else {
334 fAAFillRectIndexBuffer->unlock();
335 }
336 }
337 }
338
339 return fAAFillRectIndexBuffer;
340 }
341
342 static const uint16_t gMiterStrokeAARectIdx[] = {
343 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
344 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
345 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
346 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
347
348 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
349 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
350 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
351 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
352
353 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
354 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
355 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
356 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
357 };
358
359 /**
360 * As in miter-stroke, index = a + b, and a is the current index, b is the shift
361 * from the first index. The index layout:
362 * outer AA line: 0~3, 4~7
363 * outer edge: 8~11, 12~15
364 * inner edge: 16~19
365 * inner AA line: 20~23
366 * Following comes a bevel-stroke rect and its indices:
367 *
368 * 4 7
369 * *********************************
370 * * ______________________________ *
371 * * / 12 15 \ *
372 * * / \ *
373 * 0 * |8 16_____________________19 11 | * 3
374 * * | | | | *
375 * * | | **************** | | *
376 * * | | * 20 23 * | | *
377 * * | | * * | | *
378 * * | | * 21 22 * | | *
379 * * | | **************** | | *
380 * * | |____________________| | *
381 * 1 * |9 17 18 10| * 2
382 * * \ / *
383 * * \13 __________________________14/ *
384 * * *
385 * **********************************
386 * 5 6
387 */
388 static const uint16_t gBevelStrokeAARectIdx[] = {
389 // Draw outer AA, from outer AA line to outer edge, shift is 0.
390 0 + 0, 1 + 0, 9 + 0, 9 + 0, 8 + 0, 0 + 0,
391 1 + 0, 5 + 0, 13 + 0, 13 + 0, 9 + 0, 1 + 0,
392 5 + 0, 6 + 0, 14 + 0, 14 + 0, 13 + 0, 5 + 0,
393 6 + 0, 2 + 0, 10 + 0, 10 + 0, 14 + 0, 6 + 0,
394 2 + 0, 3 + 0, 11 + 0, 11 + 0, 10 + 0, 2 + 0,
395 3 + 0, 7 + 0, 15 + 0, 15 + 0, 11 + 0, 3 + 0,
396 7 + 0, 4 + 0, 12 + 0, 12 + 0, 15 + 0, 7 + 0,
397 4 + 0, 0 + 0, 8 + 0, 8 + 0, 12 + 0, 4 + 0,
398
399 // Draw the stroke, from outer edge to inner edge, shift is 8.
400 0 + 8, 1 + 8, 9 + 8, 9 + 8, 8 + 8, 0 + 8,
401 1 + 8, 5 + 8, 9 + 8,
402 5 + 8, 6 + 8, 10 + 8, 10 + 8, 9 + 8, 5 + 8,
403 6 + 8, 2 + 8, 10 + 8,
404 2 + 8, 3 + 8, 11 + 8, 11 + 8, 10 + 8, 2 + 8,
405 3 + 8, 7 + 8, 11 + 8,
406 7 + 8, 4 + 8, 8 + 8, 8 + 8, 11 + 8, 7 + 8,
407 4 + 8, 0 + 8, 8 + 8,
408
409 // Draw the inner AA, from inner edge to inner AA line, shift is 16.
410 0 + 16, 1 + 16, 5 + 16, 5 + 16, 4 + 16, 0 + 16,
411 1 + 16, 2 + 16, 6 + 16, 6 + 16, 5 + 16, 1 + 16,
412 2 + 16, 3 + 16, 7 + 16, 7 + 16, 6 + 16, 2 + 16,
413 3 + 16, 0 + 16, 4 + 16, 4 + 16, 7 + 16, 3 + 16,
414 };
415
aaStrokeRectIndexCount(bool miterStroke)416 int GrAARectRenderer::aaStrokeRectIndexCount(bool miterStroke) {
417 return miterStroke ? GR_ARRAY_COUNT(gMiterStrokeAARectIdx) :
418 GR_ARRAY_COUNT(gBevelStrokeAARectIdx);
419 }
420
aaStrokeRectIndexBuffer(GrGpu * gpu,bool miterStroke)421 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu, bool miterStroke) {
422 if (miterStroke) {
423 if (NULL == fAAMiterStrokeRectIndexBuffer) {
424 fAAMiterStrokeRectIndexBuffer =
425 gpu->createIndexBuffer(sizeof(gMiterStrokeAARectIdx), false);
426 if (NULL != fAAMiterStrokeRectIndexBuffer) {
427 #ifdef SK_DEBUG
428 bool updated =
429 #endif
430 fAAMiterStrokeRectIndexBuffer->updateData(gMiterStrokeAARectIdx,
431 sizeof(gMiterStrokeAARectIdx));
432 GR_DEBUGASSERT(updated);
433 }
434 }
435 return fAAMiterStrokeRectIndexBuffer;
436 } else {
437 if (NULL == fAABevelStrokeRectIndexBuffer) {
438 fAABevelStrokeRectIndexBuffer =
439 gpu->createIndexBuffer(sizeof(gBevelStrokeAARectIdx), false);
440 if (NULL != fAABevelStrokeRectIndexBuffer) {
441 #ifdef SK_DEBUG
442 bool updated =
443 #endif
444 fAABevelStrokeRectIndexBuffer->updateData(gBevelStrokeAARectIdx,
445 sizeof(gBevelStrokeAARectIdx));
446 GR_DEBUGASSERT(updated);
447 }
448 }
449 return fAABevelStrokeRectIndexBuffer;
450 }
451 }
452
geometryFillAARect(GrGpu * gpu,GrDrawTarget * target,const SkRect & rect,const SkMatrix & combinedMatrix,const SkRect & devRect,bool useVertexCoverage)453 void GrAARectRenderer::geometryFillAARect(GrGpu* gpu,
454 GrDrawTarget* target,
455 const SkRect& rect,
456 const SkMatrix& combinedMatrix,
457 const SkRect& devRect,
458 bool useVertexCoverage) {
459 GrDrawState* drawState = target->drawState();
460
461 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
462
463 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
464 if (!geo.succeeded()) {
465 GrPrintf("Failed to get space for vertices!\n");
466 return;
467 }
468
469 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
470 if (NULL == indexBuffer) {
471 GrPrintf("Failed to create index buffer!\n");
472 return;
473 }
474
475 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
476 size_t vsize = drawState->getVertexSize();
477 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
478
479 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
480 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
481
482 SkScalar inset = SkMinScalar(devRect.width(), SK_Scalar1);
483 inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
484
485 if (combinedMatrix.rectStaysRect()) {
486 // Temporarily #if'ed out. We don't want to pass in the devRect but
487 // right now it is computed in GrContext::apply_aa_to_rect and we don't
488 // want to throw away the work
489 #if 0
490 SkRect devRect;
491 combinedMatrix.mapRect(&devRect, rect);
492 #endif
493
494 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
495 set_inset_fan(fan1Pos, vsize, devRect, inset, inset);
496 } else {
497 // compute transformed (1, 0) and (0, 1) vectors
498 SkVector vec[2] = {
499 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
500 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
501 };
502
503 vec[0].normalize();
504 vec[0].scale(SK_ScalarHalf);
505 vec[1].normalize();
506 vec[1].scale(SK_ScalarHalf);
507
508 // create the rotated rect
509 fan0Pos->setRectFan(rect.fLeft, rect.fTop,
510 rect.fRight, rect.fBottom, vsize);
511 combinedMatrix.mapPointsWithStride(fan0Pos, vsize, 4);
512
513 // Now create the inset points and then outset the original
514 // rotated points
515
516 // TL
517 *((SkPoint*)((intptr_t)fan1Pos + 0 * vsize)) =
518 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) + vec[0] + vec[1];
519 *((SkPoint*)((intptr_t)fan0Pos + 0 * vsize)) -= vec[0] + vec[1];
520 // BL
521 *((SkPoint*)((intptr_t)fan1Pos + 1 * vsize)) =
522 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) + vec[0] - vec[1];
523 *((SkPoint*)((intptr_t)fan0Pos + 1 * vsize)) -= vec[0] - vec[1];
524 // BR
525 *((SkPoint*)((intptr_t)fan1Pos + 2 * vsize)) =
526 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) - vec[0] - vec[1];
527 *((SkPoint*)((intptr_t)fan0Pos + 2 * vsize)) += vec[0] + vec[1];
528 // TR
529 *((SkPoint*)((intptr_t)fan1Pos + 3 * vsize)) =
530 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) - vec[0] + vec[1];
531 *((SkPoint*)((intptr_t)fan0Pos + 3 * vsize)) += vec[0] - vec[1];
532 }
533
534 verts += sizeof(GrPoint);
535 for (int i = 0; i < 4; ++i) {
536 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
537 }
538
539 int scale;
540 if (inset < SK_ScalarHalf) {
541 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
542 SkASSERT(scale >= 0 && scale <= 255);
543 } else {
544 scale = 0xff;
545 }
546
547 GrColor innerColor;
548 if (useVertexCoverage) {
549 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
550 } else {
551 if (0xff == scale) {
552 innerColor = target->getDrawState().getColor();
553 } else {
554 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
555 }
556 }
557
558 verts += 4 * vsize;
559 for (int i = 0; i < 4; ++i) {
560 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
561 }
562
563 target->setIndexSourceToBuffer(indexBuffer);
564 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
565 kVertsPerAAFillRect,
566 kIndicesPerAAFillRect);
567 target->resetIndexSource();
568 }
569
570 namespace {
571
572 // Rotated
573 struct RectVertex {
574 GrPoint fPos;
575 GrPoint fCenter;
576 GrPoint fDir;
577 GrPoint fWidthHeight;
578 };
579
580 // Rotated
581 extern const GrVertexAttrib gAARectVertexAttribs[] = {
582 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
583 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
584 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBinding }
585 };
586
587 // Axis Aligned
588 struct AARectVertex {
589 GrPoint fPos;
590 GrPoint fOffset;
591 GrPoint fWidthHeight;
592 };
593
594 // Axis Aligned
595 extern const GrVertexAttrib gAAAARectVertexAttribs[] = {
596 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding },
597 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding },
598 };
599
600 };
601
shaderFillAARect(GrGpu * gpu,GrDrawTarget * target,const SkRect & rect,const SkMatrix & combinedMatrix)602 void GrAARectRenderer::shaderFillAARect(GrGpu* gpu,
603 GrDrawTarget* target,
604 const SkRect& rect,
605 const SkMatrix& combinedMatrix) {
606 GrDrawState* drawState = target->drawState();
607
608 SkPoint center = SkPoint::Make(rect.centerX(), rect.centerY());
609 combinedMatrix.mapPoints(¢er, 1);
610
611 // compute transformed (0, 1) vector
612 SkVector dir = { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] };
613 dir.normalize();
614
615 // compute transformed (width, 0) and (0, height) vectors
616 SkVector vec[2] = {
617 { combinedMatrix[SkMatrix::kMScaleX], combinedMatrix[SkMatrix::kMSkewY] },
618 { combinedMatrix[SkMatrix::kMSkewX], combinedMatrix[SkMatrix::kMScaleY] }
619 };
620
621 SkScalar newWidth = SkScalarHalf(rect.width() * vec[0].length()) + SK_ScalarHalf;
622 SkScalar newHeight = SkScalarHalf(rect.height() * vec[1].length()) + SK_ScalarHalf;
623 drawState->setVertexAttribs<gAARectVertexAttribs>(SK_ARRAY_COUNT(gAARectVertexAttribs));
624 SkASSERT(sizeof(RectVertex) == drawState->getVertexSize());
625
626 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
627 if (!geo.succeeded()) {
628 GrPrintf("Failed to get space for vertices!\n");
629 return;
630 }
631
632 RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
633
634 GrEffectRef* effect = GrRectEffect::Create();
635 static const int kRectAttrIndex = 1;
636 static const int kWidthIndex = 2;
637 drawState->addCoverageEffect(effect, kRectAttrIndex, kWidthIndex)->unref();
638
639 for (int i = 0; i < 4; ++i) {
640 verts[i].fCenter = center;
641 verts[i].fDir = dir;
642 verts[i].fWidthHeight.fX = newWidth;
643 verts[i].fWidthHeight.fY = newHeight;
644 }
645
646 SkRect devRect;
647 combinedMatrix.mapRect(&devRect, rect);
648
649 SkRect devBounds = {
650 devRect.fLeft - SK_ScalarHalf,
651 devRect.fTop - SK_ScalarHalf,
652 devRect.fRight + SK_ScalarHalf,
653 devRect.fBottom + SK_ScalarHalf
654 };
655
656 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
657 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
658 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
659 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
660
661 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
662 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
663 target->resetIndexSource();
664 }
665
shaderFillAlignedAARect(GrGpu * gpu,GrDrawTarget * target,const SkRect & rect,const SkMatrix & combinedMatrix)666 void GrAARectRenderer::shaderFillAlignedAARect(GrGpu* gpu,
667 GrDrawTarget* target,
668 const SkRect& rect,
669 const SkMatrix& combinedMatrix) {
670 GrDrawState* drawState = target->drawState();
671 SkASSERT(combinedMatrix.rectStaysRect());
672
673 drawState->setVertexAttribs<gAAAARectVertexAttribs>(SK_ARRAY_COUNT(gAAAARectVertexAttribs));
674 SkASSERT(sizeof(AARectVertex) == drawState->getVertexSize());
675
676 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0);
677 if (!geo.succeeded()) {
678 GrPrintf("Failed to get space for vertices!\n");
679 return;
680 }
681
682 AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
683
684 GrEffectRef* effect = GrAlignedRectEffect::Create();
685 static const int kOffsetIndex = 1;
686 drawState->addCoverageEffect(effect, kOffsetIndex)->unref();
687
688 SkRect devRect;
689 combinedMatrix.mapRect(&devRect, rect);
690
691 SkRect devBounds = {
692 devRect.fLeft - SK_ScalarHalf,
693 devRect.fTop - SK_ScalarHalf,
694 devRect.fRight + SK_ScalarHalf,
695 devRect.fBottom + SK_ScalarHalf
696 };
697
698 GrPoint widthHeight = {
699 SkScalarHalf(devRect.width()) + SK_ScalarHalf,
700 SkScalarHalf(devRect.height()) + SK_ScalarHalf
701 };
702
703 verts[0].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fTop);
704 verts[0].fOffset = SkPoint::Make(-widthHeight.fX, -widthHeight.fY);
705 verts[0].fWidthHeight = widthHeight;
706
707 verts[1].fPos = SkPoint::Make(devBounds.fLeft, devBounds.fBottom);
708 verts[1].fOffset = SkPoint::Make(-widthHeight.fX, widthHeight.fY);
709 verts[1].fWidthHeight = widthHeight;
710
711 verts[2].fPos = SkPoint::Make(devBounds.fRight, devBounds.fBottom);
712 verts[2].fOffset = widthHeight;
713 verts[2].fWidthHeight = widthHeight;
714
715 verts[3].fPos = SkPoint::Make(devBounds.fRight, devBounds.fTop);
716 verts[3].fOffset = SkPoint::Make(widthHeight.fX, -widthHeight.fY);
717 verts[3].fWidthHeight = widthHeight;
718
719 target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer());
720 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6);
721 target->resetIndexSource();
722 }
723
strokeAARect(GrGpu * gpu,GrDrawTarget * target,const SkRect & rect,const SkMatrix & combinedMatrix,const SkRect & devRect,const SkStrokeRec * stroke,bool useVertexCoverage)724 void GrAARectRenderer::strokeAARect(GrGpu* gpu,
725 GrDrawTarget* target,
726 const SkRect& rect,
727 const SkMatrix& combinedMatrix,
728 const SkRect& devRect,
729 const SkStrokeRec* stroke,
730 bool useVertexCoverage) {
731 GrVec devStrokeSize;
732 SkScalar width = stroke->getWidth();
733 if (width > 0) {
734 devStrokeSize.set(width, width);
735 combinedMatrix.mapVectors(&devStrokeSize, 1);
736 devStrokeSize.setAbs(devStrokeSize);
737 } else {
738 devStrokeSize.set(SK_Scalar1, SK_Scalar1);
739 }
740
741 const SkScalar dx = devStrokeSize.fX;
742 const SkScalar dy = devStrokeSize.fY;
743 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
744 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
745
746 // Temporarily #if'ed out. We don't want to pass in the devRect but
747 // right now it is computed in GrContext::apply_aa_to_rect and we don't
748 // want to throw away the work
749 #if 0
750 SkRect devRect;
751 combinedMatrix.mapRect(&devRect, rect);
752 #endif
753
754 SkScalar spare;
755 {
756 SkScalar w = devRect.width() - dx;
757 SkScalar h = devRect.height() - dy;
758 spare = GrMin(w, h);
759 }
760
761 SkRect devOutside(devRect);
762 devOutside.outset(rx, ry);
763
764 bool miterStroke = true;
765 // small miter limit means right angles show bevel...
766 if (stroke->getJoin() != SkPaint::kMiter_Join || stroke->getMiter() < SK_ScalarSqrt2) {
767 miterStroke = false;
768 }
769
770 if (spare <= 0 && miterStroke) {
771 this->fillAARect(gpu, target, devOutside, SkMatrix::I(),
772 devOutside, useVertexCoverage);
773 return;
774 }
775
776 SkRect devInside(devRect);
777 devInside.inset(rx, ry);
778
779 SkRect devOutsideAssist(devRect);
780
781 // For bevel-stroke, use 2 SkRect instances(devOutside and devOutsideAssist)
782 // to draw the outer of the rect. Because there are 8 vertices on the outer
783 // edge, while vertex number of inner edge is 4, the same as miter-stroke.
784 if (!miterStroke) {
785 devOutside.inset(0, ry);
786 devOutsideAssist.outset(0, ry);
787 }
788
789 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
790 devInside, useVertexCoverage, miterStroke);
791 }
792
geometryStrokeAARect(GrGpu * gpu,GrDrawTarget * target,const SkRect & devOutside,const SkRect & devOutsideAssist,const SkRect & devInside,bool useVertexCoverage,bool miterStroke)793 void GrAARectRenderer::geometryStrokeAARect(GrGpu* gpu,
794 GrDrawTarget* target,
795 const SkRect& devOutside,
796 const SkRect& devOutsideAssist,
797 const SkRect& devInside,
798 bool useVertexCoverage,
799 bool miterStroke) {
800 GrDrawState* drawState = target->drawState();
801
802 set_aa_rect_vertex_attributes(drawState, useVertexCoverage);
803
804 int innerVertexNum = 4;
805 int outerVertexNum = miterStroke ? 4 : 8;
806 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2;
807
808 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, 0);
809 if (!geo.succeeded()) {
810 GrPrintf("Failed to get space for vertices!\n");
811 return;
812 }
813 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu, miterStroke);
814 if (NULL == indexBuffer) {
815 GrPrintf("Failed to create index buffer!\n");
816 return;
817 }
818
819 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
820 size_t vsize = drawState->getVertexSize();
821 SkASSERT(sizeof(GrPoint) + sizeof(GrColor) == vsize);
822
823 // We create vertices for four nested rectangles. There are two ramps from 0 to full
824 // coverage, one on the exterior of the stroke and the other on the interior.
825 // The following pointers refer to the four rects, from outermost to innermost.
826 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
827 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + outerVertexNum * vsize);
828 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 2 * outerVertexNum * vsize);
829 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + (2 * outerVertexNum + innerVertexNum) * vsize);
830
831 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX
832 // TODO: this only really works if the X & Y margins are the same all around
833 // the rect
834 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRight);
835 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft);
836 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop);
837 if (miterStroke) {
838 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInside.fBottom);
839 } else {
840 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - devInside.fBottom);
841 }
842 SkASSERT(inset >= 0);
843 #else
844 SkScalar inset = SK_ScalarHalf;
845 #endif
846
847 if (miterStroke) {
848 // outermost
849 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
850 // inner two
851 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
852 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
853 // innermost
854 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
855 } else {
856 GrPoint* fan0AssistPos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
857 GrPoint* fan1AssistPos = reinterpret_cast<GrPoint*>(verts + (outerVertexNum + 4) * vsize);
858 // outermost
859 set_inset_fan(fan0Pos, vsize, devOutside, -SK_ScalarHalf, -SK_ScalarHalf);
860 set_inset_fan(fan0AssistPos, vsize, devOutsideAssist, -SK_ScalarHalf, -SK_ScalarHalf);
861 // outer one of the inner two
862 set_inset_fan(fan1Pos, vsize, devOutside, inset, inset);
863 set_inset_fan(fan1AssistPos, vsize, devOutsideAssist, inset, inset);
864 // inner one of the inner two
865 set_inset_fan(fan2Pos, vsize, devInside, -inset, -inset);
866 // innermost
867 set_inset_fan(fan3Pos, vsize, devInside, SK_ScalarHalf, SK_ScalarHalf);
868 }
869
870 // The outermost rect has 0 coverage
871 verts += sizeof(GrPoint);
872 for (int i = 0; i < outerVertexNum; ++i) {
873 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
874 }
875
876 int scale;
877 if (inset < SK_ScalarHalf) {
878 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
879 SkASSERT(scale >= 0 && scale <= 255);
880 } else {
881 scale = 0xff;
882 }
883
884 // The inner two rects have full coverage
885 GrColor innerColor;
886 if (useVertexCoverage) {
887 innerColor = GrColorPackRGBA(scale, scale, scale, scale);
888 } else {
889 if (0xff == scale) {
890 innerColor = target->getDrawState().getColor();
891 } else {
892 innerColor = SkAlphaMulQ(target->getDrawState().getColor(), scale);
893 }
894 }
895
896 verts += outerVertexNum * vsize;
897 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) {
898 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
899 }
900
901 // The innermost rect has 0 coverage
902 verts += (outerVertexNum + innerVertexNum) * vsize;
903 for (int i = 0; i < innerVertexNum; ++i) {
904 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
905 }
906
907 target->setIndexSourceToBuffer(indexBuffer);
908 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0,
909 totalVertexNum, aaStrokeRectIndexCount(miterStroke));
910 }
911
fillAANestedRects(GrGpu * gpu,GrDrawTarget * target,const SkRect rects[2],const SkMatrix & combinedMatrix,bool useVertexCoverage)912 void GrAARectRenderer::fillAANestedRects(GrGpu* gpu,
913 GrDrawTarget* target,
914 const SkRect rects[2],
915 const SkMatrix& combinedMatrix,
916 bool useVertexCoverage) {
917 SkASSERT(combinedMatrix.rectStaysRect());
918 SkASSERT(!rects[1].isEmpty());
919
920 SkRect devOutside, devOutsideAssist, devInside;
921 combinedMatrix.mapRect(&devOutside, rects[0]);
922 // can't call mapRect for devInside since it calls sort
923 combinedMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2);
924
925 if (devInside.isEmpty()) {
926 this->fillAARect(gpu, target, devOutside, SkMatrix::I(), devOutside, useVertexCoverage);
927 return;
928 }
929
930 this->geometryStrokeAARect(gpu, target, devOutside, devOutsideAssist,
931 devInside, useVertexCoverage, true);
932 }
933