blob: 741b83d080803e40b9b628783fd7bdee480c6bb9 [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.com9b855c72013-03-01 18:21:22 +000016static void aa_rect_attributes(bool useCoverage, GrAttribBindings* bindings,
17 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
jvanverth@google.com9b855c72013-03-01 18:21:22 +000033// position + color/coverage
34static const GrVertexAttrib kVertexAttribs[] = {
35 GrVertexAttrib(kVec2f_GrVertexAttribType, 0),
36 GrVertexAttrib(kVec4ub_GrVertexAttribType, sizeof(GrPoint))
37};
38
robertphillips@google.comf6747b02012-06-12 00:32:28 +000039};
40
41void GrAARectRenderer::reset() {
42 GrSafeSetNull(fAAFillRectIndexBuffer);
43 GrSafeSetNull(fAAStrokeRectIndexBuffer);
44}
45
robertphillips@google.com6d067302012-12-18 21:47:47 +000046static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000047 0, 1, 5, 5, 4, 0,
48 1, 2, 6, 6, 5, 1,
49 2, 3, 7, 7, 6, 2,
50 3, 0, 4, 4, 7, 3,
51 4, 5, 6, 6, 7, 4,
52};
53
robertphillips@google.com6d067302012-12-18 21:47:47 +000054static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
55static const int kVertsPerAAFillRect = 8;
56static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000057
58GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000059 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
60 sizeof(uint16_t) *
61 kNumAAFillRectsInIndexBuffer;
62
robertphillips@google.comf6747b02012-06-12 00:32:28 +000063 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000064 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000065 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000066 uint16_t* data = (uint16_t*) fAAFillRectIndexBuffer->lock();
67 bool useTempData = (NULL == data);
68 if (useTempData) {
69 data = SkNEW_ARRAY(uint16_t, kNumAAFillRectsInIndexBuffer * kIndicesPerAAFillRect);
70 }
71 for (int i = 0; i < kNumAAFillRectsInIndexBuffer; ++i) {
72 // Each AA filled rect is drawn with 8 vertices and 10 triangles (8 around
73 // the inner rect (for AA) and 2 for the inner rect.
74 int baseIdx = i * kIndicesPerAAFillRect;
75 uint16_t baseVert = (uint16_t)(i * kVertsPerAAFillRect);
76 for (int j = 0; j < kIndicesPerAAFillRect; ++j) {
77 data[baseIdx+j] = baseVert + gFillAARectIdx[j];
78 }
79 }
80 if (useTempData) {
81 if (!fAAFillRectIndexBuffer->updateData(data, kAAFillRectIndexBufferSize)) {
82 GrCrash("Can't get AA Fill Rect indices into buffer!");
83 }
84 SkDELETE_ARRAY(data);
85 } else {
86 fAAFillRectIndexBuffer->unlock();
87 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +000088 }
89 }
robertphillips@google.com6d067302012-12-18 21:47:47 +000090
robertphillips@google.comf6747b02012-06-12 00:32:28 +000091 return fAAFillRectIndexBuffer;
92}
93
robertphillips@google.com6d067302012-12-18 21:47:47 +000094static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000095 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0,
96 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0,
97 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0,
98 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0,
99
100 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4,
101 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4,
102 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4,
103 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4,
104
105 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8,
106 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8,
107 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8,
108 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8,
109};
110
111int GrAARectRenderer::aaStrokeRectIndexCount() {
112 return GR_ARRAY_COUNT(gStrokeAARectIdx);
113}
114
115GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
116 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000117 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000118 gpu->createIndexBuffer(sizeof(gStrokeAARectIdx), false);
119 if (NULL != fAAStrokeRectIndexBuffer) {
120#if GR_DEBUG
121 bool updated =
122#endif
123 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx,
124 sizeof(gStrokeAARectIdx));
125 GR_DEBUGASSERT(updated);
126 }
127 }
128 return fAAStrokeRectIndexBuffer;
129}
130
131void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000132 GrDrawTarget* target,
133 const GrRect& devRect,
134 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000135 GrDrawState* drawState = target->drawState();
136
137 GrAttribBindings bindings;
138 GrDrawState::AttribIndex attribIndex;
139 aa_rect_attributes(useVertexCoverage, &bindings, &attribIndex);
140 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
141 drawState->setAttribBindings(bindings);
142 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
143 drawState->setAttribIndex(attribIndex, 1);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000144
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000145 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000146 if (!geo.succeeded()) {
147 GrPrintf("Failed to get space for vertices!\n");
148 return;
149 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000150
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000151 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
152 if (NULL == indexBuffer) {
153 GrPrintf("Failed to create index buffer!\n");
154 return;
155 }
156
157 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000158 size_t vsize = drawState->getVertexSize();
159 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000160
161 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
162 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
163
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000164 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
165 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000166
167 verts += sizeof(GrPoint);
168 for (int i = 0; i < 4; ++i) {
169 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
170 }
171
172 GrColor innerColor;
173 if (useVertexCoverage) {
174 innerColor = 0xffffffff;
175 } else {
176 innerColor = target->getDrawState().getColor();
177 }
178
179 verts += 4 * vsize;
180 for (int i = 0; i < 4; ++i) {
181 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
182 }
183
184 target->setIndexSourceToBuffer(indexBuffer);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000185 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
186 kVertsPerAAFillRect,
187 kIndicesPerAAFillRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000188}
189
190void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000191 GrDrawTarget* target,
192 const GrRect& devRect,
193 const GrVec& devStrokeSize,
194 bool useVertexCoverage) {
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000195 GrDrawState* drawState = target->drawState();
196
bsalomon@google.com81712882012-11-01 17:12:34 +0000197 const SkScalar& dx = devStrokeSize.fX;
198 const SkScalar& dy = devStrokeSize.fY;
199 const SkScalar rx = SkScalarMul(dx, SK_ScalarHalf);
200 const SkScalar ry = SkScalarMul(dy, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000201
bsalomon@google.com81712882012-11-01 17:12:34 +0000202 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000203 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000204 SkScalar w = devRect.width() - dx;
205 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000206 spare = GrMin(w, h);
207 }
208
209 if (spare <= 0) {
210 GrRect r(devRect);
211 r.inset(-rx, -ry);
212 this->fillAARect(gpu, target, r, useVertexCoverage);
213 return;
214 }
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000215
216 GrAttribBindings bindings;
217 GrDrawState::AttribIndex attribIndex;
218 aa_rect_attributes(useVertexCoverage, &bindings, &attribIndex);
219 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
220 drawState->setAttribBindings(bindings);
221 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
222 drawState->setAttribIndex(attribIndex, 1);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000223
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000224 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000225 if (!geo.succeeded()) {
226 GrPrintf("Failed to get space for vertices!\n");
227 return;
228 }
229 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(gpu);
230 if (NULL == indexBuffer) {
231 GrPrintf("Failed to create index buffer!\n");
232 return;
233 }
234
235 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000236 size_t vsize = drawState->getVertexSize();
237 GrAssert(sizeof(GrPoint) + sizeof(GrColor) == vsize);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000238
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000239 // We create vertices for four nested rectangles. There are two ramps from 0 to full
240 // coverage, one on the exterior of the stroke and the other on the interior.
241 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000242 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
243 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
244 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
245 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
246
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000247 set_inset_fan(fan0Pos, vsize, devRect,
248 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
249 set_inset_fan(fan1Pos, vsize, devRect,
250 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
251 set_inset_fan(fan2Pos, vsize, devRect,
252 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
253 set_inset_fan(fan3Pos, vsize, devRect,
254 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000255
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000256 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000257 verts += sizeof(GrPoint);
258 for (int i = 0; i < 4; ++i) {
259 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
260 }
261
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000262 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000263 GrColor innerColor;
264 if (useVertexCoverage) {
265 innerColor = 0xffffffff;
266 } else {
267 innerColor = target->getDrawState().getColor();
268 }
269 verts += 4 * vsize;
270 for (int i = 0; i < 8; ++i) {
271 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
272 }
273
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000274 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000275 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000276 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000277 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
278 }
279
280 target->setIndexSourceToBuffer(indexBuffer);
281 target->drawIndexed(kTriangles_GrPrimitiveType,
282 0, 0, 16, aaStrokeRectIndexCount());
283}