| Index: src/core/SkConvolver.cpp
|
| diff --git a/src/core/SkConvolver.cpp b/src/core/SkConvolver.cpp
|
| index c32cc0347207a0bacc7a1e036f49384719e0e9dd..81fa9ee616841f2f847a84731945524f3ae6a92b 100644
|
| --- a/src/core/SkConvolver.cpp
|
| +++ b/src/core/SkConvolver.cpp
|
| @@ -3,22 +3,10 @@
|
| // found in the LICENSE file.
|
|
|
| #include "SkConvolver.h"
|
| +#include "SkOpts.h"
|
| #include "SkTArray.h"
|
|
|
| namespace {
|
| -
|
| - // Converts the argument to an 8-bit unsigned value by clamping to the range
|
| - // 0-255.
|
| - inline unsigned char ClampTo8(int a) {
|
| - if (static_cast<unsigned>(a) < 256) {
|
| - return a; // Avoid the extra check in the common case.
|
| - }
|
| - if (a < 0) {
|
| - return 0;
|
| - }
|
| - return 255;
|
| - }
|
| -
|
| // Stores a list of rows in a circular buffer. The usage is you write into it
|
| // by calling AdvanceRow. It will keep track of which row in the buffer it
|
| // should use next, and the total number of rows added.
|
| @@ -108,169 +96,6 @@ namespace {
|
| SkTArray<unsigned char*> fRowAddresses;
|
| };
|
|
|
| -// Convolves horizontally along a single row. The row data is given in
|
| -// |srcData| and continues for the numValues() of the filter.
|
| -template<bool hasAlpha>
|
| - void ConvolveHorizontally(const unsigned char* srcData,
|
| - const SkConvolutionFilter1D& filter,
|
| - unsigned char* outRow) {
|
| - // Loop over each pixel on this row in the output image.
|
| - int numValues = filter.numValues();
|
| - for (int outX = 0; outX < numValues; outX++) {
|
| - // Get the filter that determines the current output pixel.
|
| - int filterOffset, filterLength;
|
| - const SkConvolutionFilter1D::ConvolutionFixed* filterValues =
|
| - filter.FilterForValue(outX, &filterOffset, &filterLength);
|
| -
|
| - // Compute the first pixel in this row that the filter affects. It will
|
| - // touch |filterLength| pixels (4 bytes each) after this.
|
| - const unsigned char* rowToFilter = &srcData[filterOffset * 4];
|
| -
|
| - // Apply the filter to the row to get the destination pixel in |accum|.
|
| - int accum[4] = {0};
|
| - for (int filterX = 0; filterX < filterLength; filterX++) {
|
| - SkConvolutionFilter1D::ConvolutionFixed curFilter = filterValues[filterX];
|
| - accum[0] += curFilter * rowToFilter[filterX * 4 + 0];
|
| - accum[1] += curFilter * rowToFilter[filterX * 4 + 1];
|
| - accum[2] += curFilter * rowToFilter[filterX * 4 + 2];
|
| - if (hasAlpha) {
|
| - accum[3] += curFilter * rowToFilter[filterX * 4 + 3];
|
| - }
|
| - }
|
| -
|
| - // Bring this value back in range. All of the filter scaling factors
|
| - // are in fixed point with kShiftBits bits of fractional part.
|
| - accum[0] >>= SkConvolutionFilter1D::kShiftBits;
|
| - accum[1] >>= SkConvolutionFilter1D::kShiftBits;
|
| - accum[2] >>= SkConvolutionFilter1D::kShiftBits;
|
| - if (hasAlpha) {
|
| - accum[3] >>= SkConvolutionFilter1D::kShiftBits;
|
| - }
|
| -
|
| - // Store the new pixel.
|
| - outRow[outX * 4 + 0] = ClampTo8(accum[0]);
|
| - outRow[outX * 4 + 1] = ClampTo8(accum[1]);
|
| - outRow[outX * 4 + 2] = ClampTo8(accum[2]);
|
| - if (hasAlpha) {
|
| - outRow[outX * 4 + 3] = ClampTo8(accum[3]);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // There's a bug somewhere here with GCC autovectorization (-ftree-vectorize). We originally
|
| - // thought this was 32 bit only, but subsequent tests show that some 64 bit gcc compiles
|
| - // suffer here too.
|
| - //
|
| - // Dropping to -O2 disables -ftree-vectorize. GCC 4.6 needs noinline. https://bug.skia.org/2575
|
| - #if SK_HAS_ATTRIBUTE(optimize) && defined(SK_RELEASE)
|
| - #define SK_MAYBE_DISABLE_VECTORIZATION __attribute__((optimize("O2"), noinline))
|
| - #else
|
| - #define SK_MAYBE_DISABLE_VECTORIZATION
|
| - #endif
|
| -
|
| - SK_MAYBE_DISABLE_VECTORIZATION
|
| - static void ConvolveHorizontallyAlpha(const unsigned char* srcData,
|
| - const SkConvolutionFilter1D& filter,
|
| - unsigned char* outRow) {
|
| - return ConvolveHorizontally<true>(srcData, filter, outRow);
|
| - }
|
| -
|
| - SK_MAYBE_DISABLE_VECTORIZATION
|
| - static void ConvolveHorizontallyNoAlpha(const unsigned char* srcData,
|
| - const SkConvolutionFilter1D& filter,
|
| - unsigned char* outRow) {
|
| - return ConvolveHorizontally<false>(srcData, filter, outRow);
|
| - }
|
| -
|
| - #undef SK_MAYBE_DISABLE_VECTORIZATION
|
| -
|
| -
|
| -// Does vertical convolution to produce one output row. The filter values and
|
| -// length are given in the first two parameters. These are applied to each
|
| -// of the rows pointed to in the |sourceDataRows| array, with each row
|
| -// being |pixelWidth| wide.
|
| -//
|
| -// The output must have room for |pixelWidth * 4| bytes.
|
| -template<bool hasAlpha>
|
| - void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues,
|
| - int filterLength,
|
| - unsigned char* const* sourceDataRows,
|
| - int pixelWidth,
|
| - unsigned char* outRow) {
|
| - // We go through each column in the output and do a vertical convolution,
|
| - // generating one output pixel each time.
|
| - for (int outX = 0; outX < pixelWidth; outX++) {
|
| - // Compute the number of bytes over in each row that the current column
|
| - // we're convolving starts at. The pixel will cover the next 4 bytes.
|
| - int byteOffset = outX * 4;
|
| -
|
| - // Apply the filter to one column of pixels.
|
| - int accum[4] = {0};
|
| - for (int filterY = 0; filterY < filterLength; filterY++) {
|
| - SkConvolutionFilter1D::ConvolutionFixed curFilter = filterValues[filterY];
|
| - accum[0] += curFilter * sourceDataRows[filterY][byteOffset + 0];
|
| - accum[1] += curFilter * sourceDataRows[filterY][byteOffset + 1];
|
| - accum[2] += curFilter * sourceDataRows[filterY][byteOffset + 2];
|
| - if (hasAlpha) {
|
| - accum[3] += curFilter * sourceDataRows[filterY][byteOffset + 3];
|
| - }
|
| - }
|
| -
|
| - // Bring this value back in range. All of the filter scaling factors
|
| - // are in fixed point with kShiftBits bits of precision.
|
| - accum[0] >>= SkConvolutionFilter1D::kShiftBits;
|
| - accum[1] >>= SkConvolutionFilter1D::kShiftBits;
|
| - accum[2] >>= SkConvolutionFilter1D::kShiftBits;
|
| - if (hasAlpha) {
|
| - accum[3] >>= SkConvolutionFilter1D::kShiftBits;
|
| - }
|
| -
|
| - // Store the new pixel.
|
| - outRow[byteOffset + 0] = ClampTo8(accum[0]);
|
| - outRow[byteOffset + 1] = ClampTo8(accum[1]);
|
| - outRow[byteOffset + 2] = ClampTo8(accum[2]);
|
| - if (hasAlpha) {
|
| - unsigned char alpha = ClampTo8(accum[3]);
|
| -
|
| - // Make sure the alpha channel doesn't come out smaller than any of the
|
| - // color channels. We use premultipled alpha channels, so this should
|
| - // never happen, but rounding errors will cause this from time to time.
|
| - // These "impossible" colors will cause overflows (and hence random pixel
|
| - // values) when the resulting bitmap is drawn to the screen.
|
| - //
|
| - // We only need to do this when generating the final output row (here).
|
| - int maxColorChannel = SkTMax(outRow[byteOffset + 0],
|
| - SkTMax(outRow[byteOffset + 1],
|
| - outRow[byteOffset + 2]));
|
| - if (alpha < maxColorChannel) {
|
| - outRow[byteOffset + 3] = maxColorChannel;
|
| - } else {
|
| - outRow[byteOffset + 3] = alpha;
|
| - }
|
| - } else {
|
| - // No alpha channel, the image is opaque.
|
| - outRow[byteOffset + 3] = 0xff;
|
| - }
|
| - }
|
| - }
|
| -
|
| - void ConvolveVertically(const SkConvolutionFilter1D::ConvolutionFixed* filterValues,
|
| - int filterLength,
|
| - unsigned char* const* sourceDataRows,
|
| - int pixelWidth,
|
| - unsigned char* outRow,
|
| - bool sourceHasAlpha) {
|
| - if (sourceHasAlpha) {
|
| - ConvolveVertically<true>(filterValues, filterLength,
|
| - sourceDataRows, pixelWidth,
|
| - outRow);
|
| - } else {
|
| - ConvolveVertically<false>(filterValues, filterLength,
|
| - sourceDataRows, pixelWidth,
|
| - outRow);
|
| - }
|
| - }
|
| -
|
| } // namespace
|
|
|
| // SkConvolutionFilter1D ---------------------------------------------------------
|
| @@ -346,9 +171,7 @@ bool BGRAConvolve2D(const unsigned char* sourceData,
|
| const SkConvolutionFilter1D& filterX,
|
| const SkConvolutionFilter1D& filterY,
|
| int outputByteRowStride,
|
| - unsigned char* output,
|
| - const SkConvolutionProcs& convolveProcs,
|
| - bool useSimdIfPossible) {
|
| + unsigned char* output) {
|
|
|
| int maxYFilterSize = filterY.maxFilter();
|
|
|
| @@ -374,7 +197,7 @@ bool BGRAConvolve2D(const unsigned char* sourceData,
|
| // convolution pass yet. Somehow Windows does not like it.
|
| int rowBufferWidth = (filterX.numValues() + 15) & ~0xF;
|
| int rowBufferHeight = maxYFilterSize +
|
| - (convolveProcs.fConvolve4RowsHorizontally ? 4 : 0);
|
| + (SkOpts::convolve_4_rows_horizontally != nullptr ? 4 : 0);
|
|
|
| // check for too-big allocation requests : crbug.com/528628
|
| {
|
| @@ -410,7 +233,7 @@ bool BGRAConvolve2D(const unsigned char* sourceData,
|
|
|
| // Generate output rows until we have enough to run the current filter.
|
| while (nextXRow < filterOffset + filterLength) {
|
| - if (convolveProcs.fConvolve4RowsHorizontally &&
|
| + if (SkOpts::convolve_4_rows_horizontally != nullptr &&
|
| nextXRow + 3 < lastFilterOffset + lastFilterLength) {
|
| const unsigned char* src[4];
|
| unsigned char* outRow[4];
|
| @@ -418,24 +241,12 @@ bool BGRAConvolve2D(const unsigned char* sourceData,
|
| src[i] = &sourceData[(uint64_t)(nextXRow + i) * sourceByteRowStride];
|
| outRow[i] = rowBuffer.advanceRow();
|
| }
|
| - convolveProcs.fConvolve4RowsHorizontally(src, filterX, outRow, 4*rowBufferWidth);
|
| + SkOpts::convolve_4_rows_horizontally(src, filterX, outRow, 4*rowBufferWidth);
|
| nextXRow += 4;
|
| } else {
|
| - if (convolveProcs.fConvolveHorizontally) {
|
| - convolveProcs.fConvolveHorizontally(
|
| + SkOpts::convolve_horizontally(
|
| &sourceData[(uint64_t)nextXRow * sourceByteRowStride],
|
| filterX, rowBuffer.advanceRow(), sourceHasAlpha);
|
| - } else {
|
| - if (sourceHasAlpha) {
|
| - ConvolveHorizontallyAlpha(
|
| - &sourceData[(uint64_t)nextXRow * sourceByteRowStride],
|
| - filterX, rowBuffer.advanceRow());
|
| - } else {
|
| - ConvolveHorizontallyNoAlpha(
|
| - &sourceData[(uint64_t)nextXRow * sourceByteRowStride],
|
| - filterX, rowBuffer.advanceRow());
|
| - }
|
| - }
|
| nextXRow++;
|
| }
|
| }
|
| @@ -448,22 +259,14 @@ bool BGRAConvolve2D(const unsigned char* sourceData,
|
| unsigned char* const* rowsToConvolve =
|
| rowBuffer.GetRowAddresses(&firstRowInCircularBuffer);
|
|
|
| - // Now compute the start of the subset of those rows that the filter
|
| - // needs.
|
| + // Now compute the start of the subset of those rows that the filter needs.
|
| unsigned char* const* firstRowForFilter =
|
| &rowsToConvolve[filterOffset - firstRowInCircularBuffer];
|
|
|
| - if (convolveProcs.fConvolveVertically) {
|
| - convolveProcs.fConvolveVertically(filterValues, filterLength,
|
| - firstRowForFilter,
|
| - filterX.numValues(), curOutputRow,
|
| - sourceHasAlpha);
|
| - } else {
|
| - ConvolveVertically(filterValues, filterLength,
|
| - firstRowForFilter,
|
| - filterX.numValues(), curOutputRow,
|
| - sourceHasAlpha);
|
| - }
|
| + SkOpts::convolve_vertically(filterValues, filterLength,
|
| + firstRowForFilter,
|
| + filterX.numValues(), curOutputRow,
|
| + sourceHasAlpha);
|
| }
|
| return true;
|
| }
|
|
|