blob: 6f074e65249652f69b65b71a4895d6eed1dc3711 [file] [log] [blame]
robertphillips@google.comf6747b02012-06-12 00:32:28 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrAARectRenderer.h"
9#include "GrRefCnt.h"
10#include "GrGpu.h"
11
robertphillips@google.com4d73ac22012-06-13 18:54:08 +000012SK_DEFINE_INST_COUNT(GrAARectRenderer)
robertphillips@google.comf6747b02012-06-12 00:32:28 +000013
14namespace {
15
jvanverth@google.com054ae992013-04-01 20:06:51 +000016static void aa_rect_attributes(bool useCoverage, const GrVertexAttrib** attribs, int* count) {
17 static const GrVertexAttrib kCoverageAttribs[] = {
18 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
19 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding},
20 };
21 static const GrVertexAttrib kColorAttribs[] = {
22 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
23 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kColor_GrVertexAttribBinding},
24 };
25 *attribs = useCoverage ? kCoverageAttribs : kColorAttribs;
26 *count = 2;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000027}
28
robertphillips@google.comca47aae2012-12-12 15:58:25 +000029static void set_inset_fan(GrPoint* pts, size_t stride,
30 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000031 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
32 r.fRight - dx, r.fBottom - dy, stride);
33}
34
35};
36
37void GrAARectRenderer::reset() {
38 GrSafeSetNull(fAAFillRectIndexBuffer);
39 GrSafeSetNull(fAAStrokeRectIndexBuffer);
40}
41
robertphillips@google.com6d067302012-12-18 21:47:47 +000042static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000043 0, 1, 5, 5, 4, 0,
44 1, 2, 6, 6, 5, 1,
45 2, 3, 7, 7, 6, 2,
46 3, 0, 4, 4, 7, 3,
47 4, 5, 6, 6, 7, 4,
48};
49
robertphillips@google.com6d067302012-12-18 21:47:47 +000050static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
51static const int kVertsPerAAFillRect = 8;
52static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000053
54GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000055 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
56 sizeof(uint16_t) *
57 kNumAAFillRectsInIndexBuffer;
58
robertphillips@google.comf6747b02012-06-12 00:32:28 +000059 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000060 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000061 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000062 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
63 bool useTempData = (NULL == data);
64 if (useTempData) {
65 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
66 }
67 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
68 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
69 // the inner rect (for AA) and 2 for the inner rect.
70 int baseIdx = i * kIndicesPerAAFillRect;
71 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
72 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
73 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
74 }
75 }
76 if (useTempData) {
77 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
78 GrCrash("Can't get AA Fill Rect indices into buffer!");
79 }
80 SkDELETE_ARRAY(data);
81 } else {
82 fAAFillRectIndexBuffer->unlock();
83 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +000084 }
85 }
robertphillips@google.com6d067302012-12-18 21:47:47 +000086
robertphillips@google.comf6747b02012-06-12 00:32:28 +000087 return fAAFillRectIndexBuffer;
88}
89
robertphillips@google.com6d067302012-12-18 21:47:47 +000090static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000091 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
92 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
93 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
94 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
95
96 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
97 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
98 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
99 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
100
101 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
102 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
103 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
104 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
105};
106
107int GrAARectRenderer::aaStrokeRectIndexCount() {
108 return GR_ARRAY_COUNT(gStrokeAARectIdx);
109}
110
111GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
112 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000113 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000114 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
115 if (NULL != fAAStrokeRectIndexBuffer) {
116#if GR_DEBUG
117 bool updated =
118#endif
119 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
120 sizeof(gStrokeAARectIdx));
121 GR_DEBUGASSERT(updated);
122 }
123 }
124 return fAAStrokeRectIndexBuffer;
125}
126
127void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000128 GrDrawTarget* target,
129 const GrRect& devRect,
130 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000131 GrDrawState* drawState = target->drawState();
132
jvanverth@google.com054ae992013-04-01 20:06:51 +0000133 const GrVertexAttrib* attribs;
134 int attribCount;
135 aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
136 drawState->setVertexAttribs(attribs, attribCount);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000137
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000138 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000139 if (!geo.succeeded()) {
140 GrPrintf("Failed to get space for vertices!\n");
141 return;
142 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000143
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000144 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
145 if (NULL == indexBuffer) {
146 GrPrintf("Failed to create index buffer!\n");
147 return;
148 }
149
150 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000151 size_t vsize = drawState->getVertexSize();
152 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000153
154 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
155 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
156
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000157 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
158 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000159
160 verts += sizeof(GrPoint);
161 for (int i = 0; i < 4; ++i) {
162 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
163 }
164
165 GrColor innerColor;
166 if (useVertexCoverage) {
167 innerColor = 0xffffffff;
168 } else {
169 innerColor = target->getDrawState().getColor();
170 }
171
172 verts += 4 * vsize;
173 for (int i = 0; i < 4; ++i) {
174 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
175 }
176
177 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000178 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
179 kVertsPerAAFillRect,
180 kIndicesPerAAFillRect);
bsalomon@google.com0406b9e2013-04-02 21:00:15 +0000181 target->resetIndexSource();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000182}
183
184void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000185 GrDrawTarget* target,
186 const GrRect& devRect,
187 const GrVec& devStrokeSize,
188 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000189 GrDrawState* drawState = target->drawState();
190
bsalomon@google.com81712882012-11-01 17:12:34 +0000191 const SkScalar& dx = devStrokeSize.fX;
192 const SkScalar& dy = devStrokeSize.fY;
193 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
194 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000195
bsalomon@google.com81712882012-11-01 17:12:34 +0000196 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000197 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000198 SkScalar w = devRect.width() - dx;
199 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000200 spare = GrMin(w, h);
201 }
202
203 if (spare <= 0) {
204 GrRect r(devRect);
205 r.inset(-rx, -ry);
206 this->fillAARect(gpu, target, r, useVertexCoverage);
207 return;
208 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000209
jvanverth@google.com054ae992013-04-01 20:06:51 +0000210 const GrVertexAttrib* attribs;
211 int attribCount;
212 aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
213 drawState->setVertexAttribs(attribs, attribCount);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000214
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000215 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000216 if (!geo.succeeded()) {
217 GrPrintf("Failed to get space for vertices!\n");
218 return;
219 }
220 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
221 if (NULL == indexBuffer) {
222 GrPrintf("Failed to create index buffer!\n");
223 return;
224 }
225
226 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000227 size_t vsize = drawState->getVertexSize();
228 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000229
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000230 // We create vertices for four nested rectangles. There are two ramps from 0 to full
231 // coverage, one on the exterior of the stroke and the other on the interior.
232 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000233 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
234 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
235 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
236 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
237
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000238 set_inset_fan(fan0Pos, vsize, devRect,
239 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
240 set_inset_fan(fan1Pos, vsize, devRect,
241 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
242 set_inset_fan(fan2Pos, vsize, devRect,
243 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
244 set_inset_fan(fan3Pos, vsize, devRect,
245 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000246
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000247 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000248 verts += sizeof(GrPoint);
249 for (int i = 0; i < 4; ++i) {
250 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
251 }
252
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000253 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000254 GrColor innerColor;
255 if (useVertexCoverage) {
256 innerColor = 0xffffffff;
257 } else {
258 innerColor = target->getDrawState().getColor();
259 }
260 verts += 4 * vsize;
261 for (int i = 0; i < 8; ++i) {
262 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
263 }
264
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000265 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000266 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000267 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000268 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
269 }
270
271 target->setIndexSourceToBuffer(indexBuffer);
272 target->drawIndexed(kTriangles_GrPrimitiveType,
273 0, 0, 16, aaStrokeRectIndexCount());
274}