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