• 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 "GrRefCnt.h"
10 #include "GrGpu.h"
11 
12 SK_DEFINE_INST_COUNT(GrAARectRenderer)
13 
14 namespace {
15 
aa_rect_layout(bool useCoverage)16 static GrVertexLayout aa_rect_layout(bool useCoverage) {
17     GrVertexLayout layout = 0;
18     if (useCoverage) {
19         layout |= GrDrawState::kCoverage_VertexLayoutBit;
20     } else {
21         layout |= GrDrawState::kColor_VertexLayoutBit;
22     }
23     return layout;
24 }
25 
set_inset_fan(GrPoint * pts,size_t stride,const GrRect & r,SkScalar dx,SkScalar dy)26 static void set_inset_fan(GrPoint* pts, size_t stride,
27                           const GrRect& r, SkScalar dx, SkScalar dy) {
28     pts->setRectFan(r.fLeft + dx, r.fTop + dy,
29                     r.fRight - dx, r.fBottom - dy, stride);
30 }
31 
32 };
33 
reset()34 void GrAARectRenderer::reset() {
35     GrSafeSetNull(fAAFillRectIndexBuffer);
36     GrSafeSetNull(fAAStrokeRectIndexBuffer);
37 }
38 
39 static const uint16_t gFillAARectIdx[] = {
40     0, 1, 5, 5, 4, 0,
41     1, 2, 6, 6, 5, 1,
42     2, 3, 7, 7, 6, 2,
43     3, 0, 4, 4, 7, 3,
44     4, 5, 6, 6, 7, 4,
45 };
46 
47 static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
48 static const int kVertsPerAAFillRect = 8;
49 static const int kNumAAFillRectsInIndexBuffer = 256;
50 
aaFillRectIndexBuffer(GrGpu * gpu)51 GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
52     static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
53                                                      sizeof(uint16_t) *
54                                                      kNumAAFillRectsInIndexBuffer;
55 
56     if (NULL == fAAFillRectIndexBuffer) {
57         fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
58         if (NULL != fAAFillRectIndexBuffer) {
59             uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
60             bool useTempData = (NULL == data);
61             if (useTempData) {
62                 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
63             }
64             for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
65                 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
66                 // the inner rect (for AA) and 2 for the inner rect.
67                 int baseIdx = i * kIndicesPerAAFillRect;
68                 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
69                 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
70                     data[baseIdx+j] = baseVert + gFillAARectIdx[j];
71                 }
72             }
73             if (useTempData) {
74                 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
75                     GrCrash("Can't get AA Fill Rect indices into buffer!");
76                 }
77                 SkDELETE_ARRAY(data);
78             } else {
79                 fAAFillRectIndexBuffer->unlock();
80             }
81         }
82     }
83 
84     return fAAFillRectIndexBuffer;
85 }
86 
87 static const uint16_t gStrokeAARectIdx[] = {
88     0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
89     1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
90     2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
91     3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
92 
93     0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
94     1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
95     2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
96     3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
97 
98     0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
99     1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
100     2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
101     3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
102 };
103 
aaStrokeRectIndexCount()104 int GrAARectRenderer::aaStrokeRectIndexCount() {
105     return GR_ARRAY_COUNT(gStrokeAARectIdx);
106 }
107 
aaStrokeRectIndexBuffer(GrGpu * gpu)108 GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
109     if (NULL == fAAStrokeRectIndexBuffer) {
110         fAAStrokeRectIndexBuffer =
111                   gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
112         if (NULL != fAAStrokeRectIndexBuffer) {
113 #if GR_DEBUG
114             bool updated =
115 #endif
116             fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
117                                                  sizeof(gStrokeAARectIdx));
118             GR_DEBUGASSERT(updated);
119         }
120     }
121     return fAAStrokeRectIndexBuffer;
122 }
123 
fillAARect(GrGpu * gpu,GrDrawTarget * target,const GrRect & devRect,bool useVertexCoverage)124 void GrAARectRenderer::fillAARect(GrGpu* gpu,
125                                   GrDrawTarget* target,
126                                   const GrRect& devRect,
127                                   bool useVertexCoverage) {
128     GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
129 
130     size_t vsize = GrDrawState::VertexSize(layout);
131 
132     GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
133     if (!geo.succeeded()) {
134         GrPrintf("Failed to get space for vertices!\n");
135         return;
136     }
137 
138     GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
139     if (NULL == indexBuffer) {
140         GrPrintf("Failed to create index buffer!\n");
141         return;
142     }
143 
144     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
145 
146     GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
147     GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
148 
149     set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
150     set_inset_fan(fan1Pos, vsize, devRect,  SK_ScalarHalf,  SK_ScalarHalf);
151 
152     verts += sizeof(GrPoint);
153     for (int i = 0; i < 4; ++i) {
154         *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
155     }
156 
157     GrColor innerColor;
158     if (useVertexCoverage) {
159         innerColor = 0xffffffff;
160     } else {
161         innerColor = target->getDrawState().getColor();
162     }
163 
164     verts += 4 * vsize;
165     for (int i = 0; i < 4; ++i) {
166         *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
167     }
168 
169     target->setIndexSourceToBuffer(indexBuffer);
170     target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
171                                  kVertsPerAAFillRect,
172                                  kIndicesPerAAFillRect);
173 }
174 
strokeAARect(GrGpu * gpu,GrDrawTarget * target,const GrRect & devRect,const GrVec & devStrokeSize,bool useVertexCoverage)175 void GrAARectRenderer::strokeAARect(GrGpu* gpu,
176                                     GrDrawTarget* target,
177                                     const GrRect& devRect,
178                                     const GrVec& devStrokeSize,
179                                     bool useVertexCoverage) {
180     const SkScalar& dx = devStrokeSize.fX;
181     const SkScalar& dy = devStrokeSize.fY;
182     const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
183     const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
184 
185     SkScalar spare;
186     {
187         SkScalar w = devRect.width() - dx;
188         SkScalar h = devRect.height() - dy;
189         spare = GrMin(w, h);
190     }
191 
192     if (spare <= 0) {
193         GrRect r(devRect);
194         r.inset(-rx, -ry);
195         this->fillAARect(gpu, target, r, useVertexCoverage);
196         return;
197     }
198     GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
199     size_t vsize = GrDrawState::VertexSize(layout);
200 
201     GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
202     if (!geo.succeeded()) {
203         GrPrintf("Failed to get space for vertices!\n");
204         return;
205     }
206     GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
207     if (NULL == indexBuffer) {
208         GrPrintf("Failed to create index buffer!\n");
209         return;
210     }
211 
212     intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
213 
214     // We create vertices for four nested rectangles. There are two ramps from 0 to full
215     // coverage, one on the exterior of the stroke and the other on the interior.
216     // The following pointers refer to the four rects, from outermost to innermost.
217     GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
218     GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
219     GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
220     GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
221 
222     set_inset_fan(fan0Pos, vsize, devRect,
223                   -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
224     set_inset_fan(fan1Pos, vsize, devRect,
225                   -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
226     set_inset_fan(fan2Pos, vsize, devRect,
227                   rx - SK_ScalarHalf,  ry - SK_ScalarHalf);
228     set_inset_fan(fan3Pos, vsize, devRect,
229                   rx + SK_ScalarHalf,  ry + SK_ScalarHalf);
230 
231     // The outermost rect has 0 coverage
232     verts += sizeof(GrPoint);
233     for (int i = 0; i < 4; ++i) {
234         *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
235     }
236 
237     // The inner two rects have full coverage
238     GrColor innerColor;
239     if (useVertexCoverage) {
240         innerColor = 0xffffffff;
241     } else {
242         innerColor = target->getDrawState().getColor();
243     }
244     verts += 4 * vsize;
245     for (int i = 0; i < 8; ++i) {
246         *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
247     }
248 
249     // The innermost rect has full coverage
250     verts += 8 * vsize;
251     for (int i = 0; i < 4; ++i) {
252         *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
253     }
254 
255     target->setIndexSourceToBuffer(indexBuffer);
256     target->drawIndexed(kTriangles_GrPrimitiveType,
257                         0, 0, 16, aaStrokeRectIndexCount());
258 }
259