blob: 0093b08078ed472d54a9ed1830928b57c6612e81 [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);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000181}
182
183void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000184 GrDrawTarget* target,
185 const GrRect& devRect,
186 const GrVec& devStrokeSize,
187 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000188 GrDrawState* drawState = target->drawState();
189
bsalomon@google.com81712882012-11-01 17:12:34 +0000190 const SkScalar& dx = devStrokeSize.fX;
191 const SkScalar& dy = devStrokeSize.fY;
192 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
193 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000194
bsalomon@google.com81712882012-11-01 17:12:34 +0000195 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000196 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000197 SkScalar w = devRect.width() - dx;
198 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000199 spare = GrMin(w, h);
200 }
201
202 if (spare <= 0) {
203 GrRect r(devRect);
204 r.inset(-rx, -ry);
205 this->fillAARect(gpu, target, r, useVertexCoverage);
206 return;
207 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000208
jvanverth@google.com054ae992013-04-01 20:06:51 +0000209 const GrVertexAttrib* attribs;
210 int attribCount;
211 aa_rect_attributes(useVertexCoverage, &attribs, &attribCount);
212 drawState->setVertexAttribs(attribs, attribCount);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000213
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000214 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000215 if (!geo.succeeded()) {
216 GrPrintf("Failed to get space for vertices!\n");
217 return;
218 }
219 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
220 if (NULL == indexBuffer) {
221 GrPrintf("Failed to create index buffer!\n");
222 return;
223 }
224
225 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000226 size_t vsize = drawState->getVertexSize();
227 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000228
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000229 // We create vertices for four nested rectangles. There are two ramps from 0 to full
230 // coverage, one on the exterior of the stroke and the other on the interior.
231 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000232 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
233 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
234 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
235 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
236
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000237 set_inset_fan(fan0Pos, vsize, devRect,
238 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
239 set_inset_fan(fan1Pos, vsize, devRect,
240 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
241 set_inset_fan(fan2Pos, vsize, devRect,
242 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
243 set_inset_fan(fan3Pos, vsize, devRect,
244 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000245
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000246 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000247 verts += sizeof(GrPoint);
248 for (int i = 0; i < 4; ++i) {
249 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
250 }
251
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000252 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000253 GrColor innerColor;
254 if (useVertexCoverage) {
255 innerColor = 0xffffffff;
256 } else {
257 innerColor = target->getDrawState().getColor();
258 }
259 verts += 4 * vsize;
260 for (int i = 0; i < 8; ++i) {
261 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
262 }
263
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000264 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000265 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000266 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
268 }
269
270 target->setIndexSourceToBuffer(indexBuffer);
271 target->drawIndexed(kTriangles_GrPrimitiveType,
272 0, 0, 16, aaStrokeRectIndexCount());
273}