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 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 43 int SkCoverageDeltaMask::ExpandWidth(int width) { 44 int result = width + PADDING * 2; 45 return result + (SIMD_WIDTH - result % SIMD_WIDTH) % SIMD_WIDTH; 46 } 47 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 53 bool SkCoverageDeltaMask::Suitable(const SkIRect& bounds) { 54 return bounds.width() <= SUITABLE_WIDTH && CanHandle(bounds); 55 } 56 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. 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