GrAARectRenderer.cpp revision 363e546ed626b6dbbc42f5db87b3594bc0b5944b
1/*
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
12SK_DEFINE_INST_COUNT(GrAARectRenderer)
13
14namespace {
15
16static GrVertexLayout aa_rect_layout(bool useCoverage) {
17    GrVertexLayout layout = 0;
18    if (useCoverage) {
19        layout |= GrDrawTarget::kCoverage_VertexLayoutBit;
20    } else {
21        layout |= GrDrawTarget::kColor_VertexLayoutBit;
22    }
23    return layout;
24}
25
26static void set_inset_fan(GrPoint* pts, size_t stride,
27                          const GrRect& r, SkScalar dx, SkScalar dy) {
28    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
39static const uint16_t gFillAARectIdx[] = {
40    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
47static const int kIndicesPerAAFillRect = GR_ARRAY_COUNT(gFillAARectIdx);
48static const int kVertsPerAAFillRect = 8;
49static const int kNumAAFillRectsInIndexBuffer = 256;
50
51GrIndexBuffer* GrAARectRenderer::aaFillRectIndexBuffer(GrGpu* gpu) {
52    static const size_t kAAFillRectIndexBufferSize = kIndicesPerAAFillRect *
53                                                     sizeof(uint16_t) *
54                                                     kNumAAFillRectsInIndexBuffer;
55
56    if (NULL == fAAFillRectIndexBuffer) {
57        fAAFillRectIndexBuffer = gpu->createIndexBuffer(kAAFillRectIndexBufferSize, false);
58        if (NULL != fAAFillRectIndexBuffer) {
59            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            }
81        }
82    }
83
84    return fAAFillRectIndexBuffer;
85}
86
87static const uint16_t gStrokeAARectIdx[] = {
88    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) {
110        fAAStrokeRectIndexBuffer =
111                  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,
125                                  GrDrawTarget* target,
126                                  const GrRect& devRect,
127                                  bool useVertexCoverage) {
128    GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
129
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    }
137
138    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
149    set_inset_fan(fan0Pos, vsize, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
150    set_inset_fan(fan1Pos, vsize, devRect,  SK_ScalarHalf,  SK_ScalarHalf);
151
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);
170    target->drawIndexedInstances(kTriangles_GrPrimitiveType, 1,
171                                 kVertsPerAAFillRect,
172                                 kIndicesPerAAFillRect);
173}
174
175void GrAARectRenderer::strokeAARect(GrGpu* gpu,
176                                    GrDrawTarget* target,
177                                    const GrRect& devRect,
178                                    const GrVec& devStrokeSize,
179                                    bool useVertexCoverage) {
180    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);
184
185    SkScalar spare;
186    {
187        SkScalar w = devRect.width() - dx;
188        SkScalar h = devRect.height() - dy;
189        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    }
198    GrVertexLayout layout = aa_rect_layout(useVertexCoverage);
199    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
214    // 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.
217    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
222    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);
230
231    // The outermost rect has 0 coverage
232    verts += sizeof(GrPoint);
233    for (int i = 0; i < 4; ++i) {
234        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
235    }
236
237    // The inner two rects have full coverage
238    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
249    // The innermost rect has full coverage
250    verts += 8 * vsize;
251    for (int i = 0; i < 4; ++i) {
252        *reinterpret_cast<GrColor*>(verts + i * vsize) = 0;
253    }
254
255    target->setIndexSourceToBuffer(indexBuffer);
256    target->drawIndexed(kTriangles_GrPrimitiveType,
257                        0, 0, 16, aaStrokeRectIndexCount());
258}
259