blob: d23c4b4496deadc52c0aa2ec626b6e4dcc9041ec [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
robertphillips@google.comca47aae2012-12-12 15:58:25 +000016static GrVertexLayout aa_rect_layout(bool useCoverage) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000017 GrVertexLayout layout = 0;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000018 if (useCoverage) {
jvanverth@google.comcc782382013-01-28 20:39:48 +000019 layout |= GrDrawState::kCoverage_VertexLayoutBit;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000020 } else {
jvanverth@google.comcc782382013-01-28 20:39:48 +000021 layout |= GrDrawState::kColor_VertexLayoutBit;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000022 }
23 return layout;
24}
25
robertphillips@google.comca47aae2012-12-12 15:58:25 +000026static void set_inset_fan(GrPoint* pts, size_t stride,
27 const GrRect& r, SkScalar dx, SkScalar dy) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000028 pts->setRectFan(r.fLeft + dx, r.fTop + dy,
29 r.fRight - dx, r.fBottom - dy, stride);
30}
31
32};
33
34void GrAARectRenderer::reset() {
35 GrSafeSetNull(fAAFillRectIndexBuffer);
36 GrSafeSetNull(fAAStrokeRectIndexBuffer);
37}
38
robertphillips@google.com6d067302012-12-18 21:47:47 +000039static const uint16_t gFillAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000040 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
robertphillips@google.com6d067302012-12-18 21:47:47 +000047static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
48static const int kVertsPerAAFillRect = 8;
49static const int kNumAAFillRectsInIndexBuffer = 256;
robertphillips@google.comf6747b02012-06-12 00:32:28 +000050
51GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000052 static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
53 sizeof(uint16_t) *
54 kNumAAFillRectsInIndexBuffer;
55
robertphillips@google.comf6747b02012-06-12 00:32:28 +000056 if (NULL == fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000057 fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
robertphillips@google.comf6747b02012-06-12 00:32:28 +000058 if (NULL != fAAFillRectIndexBuffer) {
robertphillips@google.com6d067302012-12-18 21:47:47 +000059 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 }
robertphillips@google.comf6747b02012-06-12 00:32:28 +000081 }
82 }
robertphillips@google.com6d067302012-12-18 21:47:47 +000083
robertphillips@google.comf6747b02012-06-12 00:32:28 +000084 return fAAFillRectIndexBuffer;
85}
86
robertphillips@google.com6d067302012-12-18 21:47:47 +000087static const uint16_t gStrokeAARectIdx[] = {
robertphillips@google.comf6747b02012-06-12 00:32:28 +000088 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
104int GrAARectRenderer::aaStrokeRectIndexCount() {
105 return GR_ARRAY_COUNT(gStrokeAARectIdx);
106}
107
108GrIndexBuffer* GrAARectRenderer::aaStrokeRectIndexBuffer(GrGpu* gpu) {
109 if (NULL == fAAStrokeRectIndexBuffer) {
rmistry@google.comd6176b02012-08-23 18:14:13 +0000110 fAAStrokeRectIndexBuffer =
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000111 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
124void GrAARectRenderer::fillAARect(GrGpu* gpu,
robertphillips@google.comf69a11b2012-06-15 13:58:07 +0000125 GrDrawTarget* target,
126 const GrRect& devRect,
127 bool useVertexCoverage) {
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000128 GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000129 target->drawState()->setVertexLayout(layout);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000130
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000131 GrDrawTarget::AutoReleaseGeometry geo(target, 8, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000132 if (!geo.succeeded()) {
133 GrPrintf("Failed to get space for vertices!\n");
134 return;
135 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000136
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000137 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
138 if (NULL == indexBuffer) {
139 GrPrintf("Failed to create index buffer!\n");
140 return;
141 }
142
143 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000144 size_t vsize = target->getDrawState().getVertexSize();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000145
146 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
147 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
148
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000149 set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
150 set_inset_fan(fan1Pos, vsize, devRect, SK_ScalarHalf, SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000151
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);
robertphillips@google.com6d067302012-12-18 21:47:47 +0000170 target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
171 kVertsPerAAFillRect,
172 kIndicesPerAAFillRect);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000173}
174
175void GrAARectRenderer::strokeAARect(GrGpu* gpu,
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000176 GrDrawTarget* target,
177 const GrRect& devRect,
178 const GrVec& devStrokeSize,
179 bool useVertexCoverage) {
bsalomon@google.com81712882012-11-01 17:12:34 +0000180 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);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000184
bsalomon@google.com81712882012-11-01 17:12:34 +0000185 SkScalar spare;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000186 {
bsalomon@google.com81712882012-11-01 17:12:34 +0000187 SkScalar w = devRect.width() - dx;
188 SkScalar h = devRect.height() - dy;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000189 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 }
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000198 GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000199 target->drawState()->setVertexLayout(layout);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000200
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000201 GrDrawTarget::AutoReleaseGeometry geo(target, 16, 0);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000202 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());
jvanverth@google.comb75b0a02013-02-05 20:33:30 +0000213 size_t vsize = target->getDrawState().getVertexSize();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000214
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000215 // We create vertices for four nested rectangles. There are two ramps from 0 to full
216 // coverage, one on the exterior of the stroke and the other on the interior.
217 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000218 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
219 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
220 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
221 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
222
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000223 set_inset_fan(fan0Pos, vsize, devRect,
224 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
225 set_inset_fan(fan1Pos, vsize, devRect,
226 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
227 set_inset_fan(fan2Pos, vsize, devRect,
228 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
229 set_inset_fan(fan3Pos, vsize, devRect,
230 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000231
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000232 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000233 verts += sizeof(GrPoint);
234 for (int i = 0; i < 4; ++i) {
235 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
236 }
237
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000238 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000239 GrColor innerColor;
240 if (useVertexCoverage) {
241 innerColor = 0xffffffff;
242 } else {
243 innerColor = target->getDrawState().getColor();
244 }
245 verts += 4 * vsize;
246 for (int i = 0; i < 8; ++i) {
247 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
248 }
249
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000250 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000251 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000252 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000253 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
254 }
255
256 target->setIndexSourceToBuffer(indexBuffer);
257 target->drawIndexed(kTriangles_GrPrimitiveType,
258 0, 0, 16, aaStrokeRectIndexCount());
259}