• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&center, 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