Home | History | Annotate | Download | only in core
      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