blob: b9d17f8802b0718e915d2eff42cc8d5eb3bfe776 [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) {
19 layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
20 } else {
21 layout |= GrDrawTarget::kColor_VertexLayoutBit;
22 }
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);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000129
130 size_t vsize = GrDrawTarget::VertexSize(layout);
131
132 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0);
133 if (!geo.succeeded()) {
134 GrPrintf("Failed to get space for vertices!\n");
135 return;
136 }
robertphillips@google.com6d067302012-12-18 21:47:47 +0000137
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000138 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(gpu);
139 if (NULL == indexBuffer) {
140 GrPrintf("Failed to create index buffer!\n");
141 return;
142 }
143
144 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices());
145
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);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000199 size_t vsize = GrDrawTarget::VertexSize(layout);
200
201 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0);
202 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());
213
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000214 // We create vertices for four nested rectangles. There are two ramps from 0 to full
215 // coverage, one on the exterior of the stroke and the other on the interior.
216 // The following pointers refer to the four rects, from outermost to innermost.
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000217 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts);
218 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize);
219 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize);
220 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize);
221
robertphillips@google.comca47aae2012-12-12 15:58:25 +0000222 set_inset_fan(fan0Pos, vsize, devRect,
223 -rx - SK_ScalarHalf, -ry - SK_ScalarHalf);
224 set_inset_fan(fan1Pos, vsize, devRect,
225 -rx + SK_ScalarHalf, -ry + SK_ScalarHalf);
226 set_inset_fan(fan2Pos, vsize, devRect,
227 rx - SK_ScalarHalf, ry - SK_ScalarHalf);
228 set_inset_fan(fan3Pos, vsize, devRect,
229 rx + SK_ScalarHalf, ry + SK_ScalarHalf);
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000230
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000231 // The outermost rect has 0 coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000232 verts += sizeof(GrPoint);
233 for (int i = 0; i < 4; ++i) {
234 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
235 }
236
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000237 // The inner two rects have full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000238 GrColor innerColor;
239 if (useVertexCoverage) {
240 innerColor = 0xffffffff;
241 } else {
242 innerColor = target->getDrawState().getColor();
243 }
244 verts += 4 * vsize;
245 for (int i = 0; i < 8; ++i) {
246 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor;
247 }
248
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000249 // The innermost rect has full coverage
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000250 verts += 8 * vsize;
bsalomon@google.come7249bd2012-08-16 15:28:54 +0000251 for (int i = 0; i < 4; ++i) {
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000252 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
253 }
254
255 target->setIndexSourceToBuffer(indexBuffer);
256 target->drawIndexed(kTriangles_GrPrimitiveType,
257 0, 0, 16, aaStrokeRectIndexCount());
258}