blob: b4f02ba8cca7f10c8b6fd5c1f0e362e07c83e679 [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
skia.committer@gmail.comf140f182013-03-02 07:01:56 +000016static void aa_rect_attributes(bool useCoverage, GrAttribBindings* bindings,
jvanverth@google.com9b855c72013-03-01 18:21:22 +000017 GrDrawState::AttribIndex* index) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000018 if (useCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +000019 *bindings = GrDrawState::kCoverage_AttribBindingsBit;
20 *index = GrDrawState::kCoverage_AttribIndex;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000021 } else {
jvanverth@google.com9b855c72013-03-01 18:21:22 +000022 *bindings = GrDrawState::kColor_AttribBindingsBit;
23 *index = GrDrawState::kColor_AttribIndex;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000024 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +000025}
26
robertphillips@google.comca47aae2012-12-12 15:58:25 +000027static void set_inset_fan(GrPoint* pts, size_t stride,
28 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000029 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
30 r.fRight - dx, r.fBottom - dy, stride);
31}
32
33};
34
35void GrAARectRenderer::reset() {
36 GrSafeSetNull(fAAFillRectIndexBuffer);
37 GrSafeSetNull(fAAStrokeRectIndexBuffer);
38}
39
robertphillips@google.com6d067302012-12-18 21:47:47 +000040static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000041 0, 1, 5, 5, 4, 0,
42 1, 2, 6, 6, 5, 1,
43 2, 3, 7, 7, 6, 2,
44 3, 0, 4, 4, 7, 3,
45 4, 5, 6, 6, 7, 4,
46};
47
robertphillips@google.com6d067302012-12-18 21:47:47 +000048static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
49static const int kVertsPerAAFillRect = 8;
50static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000051
52GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000053 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
54 sizeof(uint16_t) *
55 kNumAAFillRectsInIndexBuffer;
56
robertphillips@google.comf6747b02012-06-12 00:32:28 +000057 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000058 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000059 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000060 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
61 bool useTempData = (NULL == data);
62 if (useTempData) {
63 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
64 }
65 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
66 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
67 // the inner rect (for AA) and 2 for the inner rect.
68 int baseIdx = i * kIndicesPerAAFillRect;
69 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
70 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
71 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
72 }
73 }
74 if (useTempData) {
75 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
76 GrCrash("Can't get AA Fill Rect indices into buffer!");
77 }
78 SkDELETE_ARRAY(data);
79 } else {
80 fAAFillRectIndexBuffer->unlock();
81 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +000082 }
83 }
robertphillips@google.com6d067302012-12-18 21:47:47 +000084
robertphillips@google.comf6747b02012-06-12 00:32:28 +000085 return fAAFillRectIndexBuffer;
86}
87
robertphillips@google.com6d067302012-12-18 21:47:47 +000088static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000089 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
90 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
91 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
92 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
93
94 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
95 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
96 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
97 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
98
99 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
100 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
101 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
102 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
103};
104
105int GrAARectRenderer::aaStrokeRectIndexCount() {
106 return GR_ARRAY_COUNT(gStrokeAARectIdx);
107}
108
109GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
110 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000111 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000112 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
113 if (NULL != fAAStrokeRectIndexBuffer) {
114#if GR_DEBUG
115 bool updated =
116#endif
117 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
118 sizeof(gStrokeAARectIdx));
119 GR_DEBUGASSERT(updated);
120 }
121 }
122 return fAAStrokeRectIndexBuffer;
123}
124
125void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000126 GrDrawTarget* target,
127 const GrRect& devRect,
128 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000129 GrDrawState* drawState = target->drawState();
130
jvanverth@google.com9b98c1b2013-03-01 18:54:50 +0000131 // position + color/coverage
132 static const GrVertexAttrib kVertexAttribs[] = {
jvanverth@google.com3b0d6312013-03-01 20:30:01 +0000133 {kVec2f_GrVertexAttribType, 0},
134 {kVec4ub_GrVertexAttribType, sizeof(GrPoint)}
jvanverth@google.com9b98c1b2013-03-01 18:54:50 +0000135 };
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000136 GrAttribBindings bindings;
137 GrDrawState::AttribIndex attribIndex;
138 aa_rect_attributes(useVertexCoverage, &bindings, &attribIndex);
139 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
140 drawState->setAttribBindings(bindings);
141 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
142 drawState->setAttribIndex(attribIndex, 1);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000143
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000144 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000145 if (!geo.succeeded()) {
146 GrPrintf("Failed to get space for vertices!\n");
147 return;
148 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000149
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000150 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
151 if (NULL == indexBuffer) {
152 GrPrintf("Failed to create index buffer!\n");
153 return;
154 }
155
156 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000157 size_t vsize = drawState->getVertexSize();
158 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000159
160 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
161 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
162
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000163 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
164 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000165
166 verts += sizeof(GrPoint);
167 for (int i = 0; i < 4; ++i) {
168 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
169 }
170
171 GrColor innerColor;
172 if (useVertexCoverage) {
173 innerColor = 0xffffffff;
174 } else {
175 innerColor = target->getDrawState().getColor();
176 }
177
178 verts += 4 * vsize;
179 for (int i = 0; i < 4; ++i) {
180 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
181 }
182
183 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000184 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
185 kVertsPerAAFillRect,
186 kIndicesPerAAFillRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000187}
188
189void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000190 GrDrawTarget* target,
191 const GrRect& devRect,
192 const GrVec& devStrokeSize,
193 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000194 GrDrawState* drawState = target->drawState();
195
bsalomon@google.com81712882012-11-01 17:12:34 +0000196 const SkScalar& dx = devStrokeSize.fX;
197 const SkScalar& dy = devStrokeSize.fY;
198 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
199 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000200
bsalomon@google.com81712882012-11-01 17:12:34 +0000201 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000202 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000203 SkScalar w = devRect.width() - dx;
204 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000205 spare = GrMin(w, h);
206 }
207
208 if (spare <= 0) {
209 GrRect r(devRect);
210 r.inset(-rx, -ry);
211 this->fillAARect(gpu, target, r, useVertexCoverage);
212 return;
213 }
skia.committer@gmail.comf140f182013-03-02 07:01:56 +0000214
jvanverth@google.com9b98c1b2013-03-01 18:54:50 +0000215 // position + color/coverage
216 static const GrVertexAttrib kVertexAttribs[] = {
jvanverth@google.com3b0d6312013-03-01 20:30:01 +0000217 {kVec2f_GrVertexAttribType, 0},
218 {kVec4ub_GrVertexAttribType, sizeof(GrPoint)}
jvanverth@google.com9b98c1b2013-03-01 18:54:50 +0000219 };
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000220 GrAttribBindings bindings;
221 GrDrawState::AttribIndex attribIndex;
222 aa_rect_attributes(useVertexCoverage, &bindings, &attribIndex);
223 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
224 drawState->setAttribBindings(bindings);
225 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
226 drawState->setAttribIndex(attribIndex, 1);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000227
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000228 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000229 if (!geo.succeeded()) {
230 GrPrintf("Failed to get space for vertices!\n");
231 return;
232 }
233 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
234 if (NULL == indexBuffer) {
235 GrPrintf("Failed to create index buffer!\n");
236 return;
237 }
238
239 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000240 size_t vsize = drawState->getVertexSize();
241 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000242
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000243 // We create vertices for four nested rectangles. There are two ramps from 0 to full
244 // coverage, one on the exterior of the stroke and the other on the interior.
245 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000246 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
247 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
248 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
249 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
250
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000251 set_inset_fan(fan0Pos, vsize, devRect,
252 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
253 set_inset_fan(fan1Pos, vsize, devRect,
254 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
255 set_inset_fan(fan2Pos, vsize, devRect,
256 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
257 set_inset_fan(fan3Pos, vsize, devRect,
258 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000259
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000260 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000261 verts += sizeof(GrPoint);
262 for (int i = 0; i < 4; ++i) {
263 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
264 }
265
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000266 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000267 GrColor innerColor;
268 if (useVertexCoverage) {
269 innerColor = 0xffffffff;
270 } else {
271 innerColor = target->getDrawState().getColor();
272 }
273 verts += 4 * vsize;
274 for (int i = 0; i < 8; ++i) {
275 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
276 }
277
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000278 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000279 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000280 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000281 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
282 }
283
284 target->setIndexSourceToBuffer(indexBuffer);
285 target->drawIndexed(kTriangles_GrPrimitiveType,
286 0, 0, 16, aaStrokeRectIndexCount());
287}