1 /*
2 * Copyright 2017 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 "SkCoverageDelta.h"
9
SkCoverageDeltaList(SkArenaAlloc * alloc,int top,int bottom,bool forceRLE)10 SkCoverageDeltaList::SkCoverageDeltaList(SkArenaAlloc* alloc, int top, int bottom, bool forceRLE) {
11 fAlloc = alloc;
12 fTop = top;
13 fBottom = bottom;
14 fForceRLE = forceRLE;
15
16 // Init the anti-rect to be empty
17 fAntiRect.fY = bottom;
18 fAntiRect.fHeight = 0;
19
20 fSorted = fAlloc->makeArrayDefault<bool>(bottom - top);
21 fCounts = fAlloc->makeArrayDefault<int>((bottom - top) * 2);
22 fMaxCounts = fCounts + bottom - top;
23 fRows = fAlloc->makeArrayDefault<SkCoverageDelta*>(bottom - top) - top;
24 fRows[top] = fAlloc->makeArrayDefault<SkCoverageDelta>(INIT_ROW_SIZE * (bottom - top));
25
26 memset(fSorted, true, bottom - top);
27 memset(fCounts, 0, sizeof(int) * (bottom - top));
28
29 // Minus top so we can directly use fCounts[y] instead of fCounts[y - fTop].
30 // Same for fMaxCounts, fRows, and fSorted.
31 fSorted -= top;
32 fCounts -= top;
33 fMaxCounts -= top;
34
35 for(int y = top; y < bottom; ++y) {
36 fMaxCounts[y] = INIT_ROW_SIZE;
37 }
38 for(int y = top + 1; y < bottom; ++y) {
39 fRows[y] = fRows[y - 1] + INIT_ROW_SIZE;
40 }
41 }
42
ExpandWidth(int width)43 int SkCoverageDeltaMask::ExpandWidth(int width) {
44 int result = width + PADDING * 2;
45 return result + (SIMD_WIDTH - result % SIMD_WIDTH) % SIMD_WIDTH;
46 }
47
CanHandle(const SkIRect & bounds)48 bool SkCoverageDeltaMask::CanHandle(const SkIRect& bounds) {
49 // Expand width so we don't have to worry about the boundary
50 return ExpandWidth(bounds.width()) * bounds.height() + PADDING * 2 < MAX_MASK_SIZE;
51 }
52
Suitable(const SkIRect & bounds)53 bool SkCoverageDeltaMask::Suitable(const SkIRect& bounds) {
54 return bounds.width() <= SUITABLE_WIDTH && CanHandle(bounds);
55 }
56
SkCoverageDeltaMask(SkArenaAlloc * alloc,const SkIRect & bounds)57 SkCoverageDeltaMask::SkCoverageDeltaMask(SkArenaAlloc* alloc, const SkIRect& bounds) {
58 SkASSERT(CanHandle(bounds));
59
60 fBounds = bounds;
61
62 // Init the anti-rect to be empty
63 fAntiRect.fY = fBounds.fBottom;
64 fAntiRect.fHeight = 0;
65
66 fExpandedWidth = ExpandWidth(fBounds.width());
67
68 int size = fExpandedWidth * bounds.height() + PADDING * 2;
69 fDeltaStorage = alloc->makeArray<SkFixed>(size);
70 fMask = alloc->makeArrayDefault<SkAlpha>(size);
71
72 // Add PADDING columns so we may access fDeltas[index(-PADDING, 0)]
73 // Minus index(fBounds.fLeft, fBounds.fTop) so we can directly access fDeltas[index(x, y)]
74 fDeltas = fDeltaStorage + PADDING - this->index(fBounds.fLeft, fBounds.fTop);
75 }
76
77 // TODO As this function is so performance-critical (and we're thinking so much about SIMD), use
78 // SkOpts framework to compile multiple versions of this function so we can choose the best one
79 // available at runtime.
convertCoverageToAlpha(bool isEvenOdd,bool isInverse,bool isConvex)80 void SkCoverageDeltaMask::convertCoverageToAlpha(bool isEvenOdd, bool isInverse, bool isConvex) {
81 SkFixed* deltaRow = &this->delta(fBounds.fLeft, fBounds.fTop);
82 SkAlpha* maskRow = fMask;
83 for(int iy = 0; iy < fBounds.height(); ++iy) {
84 // If we're inside fAntiRect, blit it to the mask and advance to its bottom
85 if (fAntiRect.fHeight && iy == fAntiRect.fY - fBounds.fTop) {
86 // Blit the mask
87 int L = fAntiRect.fX - fBounds.fLeft;
88 for(int i = 0; i < fAntiRect.fHeight; ++i) {
89 sk_bzero(maskRow, fBounds.width());
90 SkAlpha* tMask = maskRow + L;
91 if (fAntiRect.fLeftAlpha) {
92 tMask[0] = fAntiRect.fLeftAlpha;
93 }
94 memset(tMask + 1, 0xff, fAntiRect.fWidth);
95 if (fAntiRect.fRightAlpha) {
96 tMask[fAntiRect.fWidth + 1] = fAntiRect.fRightAlpha;
97 }
98 maskRow += fBounds.width();
99 }
100
101 // Advance to the bottom (maskRow is already advanced to the bottom).
102 deltaRow += fExpandedWidth * fAntiRect.fHeight;
103 iy += fAntiRect.fHeight - 1; // -1 because we'll ++iy after continue
104 continue;
105 }
106
107 // Otherwise, cumulate deltas into coverages, and convert them into alphas
108 SkFixed c[SIMD_WIDTH] = {0}; // prepare SIMD_WIDTH coverages at a time
109 for(int ix = 0; ix < fExpandedWidth; ix += SIMD_WIDTH) {
110 // Future todo: is it faster to process SIMD_WIDTH rows at a time so we can use SIMD
111 // for coverage accumulation?
112
113 // Cumulate deltas to get SIMD_WIDTH new coverages
114 c[0] = c[SIMD_WIDTH - 1] + deltaRow[ix];
115 for(int j = 1; j < SIMD_WIDTH; ++j) {
116 c[j] = c[j - 1] + deltaRow[ix + j];
117 }
118
119 using SkNi = SkNx<SIMD_WIDTH, int>;
120 SkNi cn = SkNi::Load(c);
121 SkNi an = isConvex ? ConvexCoverageToAlpha(cn, isInverse)
122 : CoverageToAlpha(cn, isEvenOdd, isInverse);
123 SkNx_cast<SkAlpha>(an).store(maskRow + ix);
124 }
125
126 // Finally, advance to the next row
127 deltaRow += fExpandedWidth;
128 maskRow += fBounds.width();
129 }
130 }
131