| Index: src/core/SkColorMatrixFilterRowMajor255.cpp
|
| diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/core/SkColorMatrixFilterRowMajor255.cpp
|
| similarity index 70%
|
| copy from src/effects/SkColorMatrixFilter.cpp
|
| copy to src/core/SkColorMatrixFilterRowMajor255.cpp
|
| index a0878a5044c5c363a74d8132f1cbebcb9da10b52..6fdfa0b446195ee6792900e688ac608a75976126 100644
|
| --- a/src/effects/SkColorMatrixFilter.cpp
|
| +++ b/src/core/SkColorMatrixFilterRowMajor255.cpp
|
| @@ -5,8 +5,7 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| -#include "SkColorMatrixFilter.h"
|
| -#include "SkColorMatrix.h"
|
| +#include "SkColorMatrixFilterRowMajor255.h"
|
| #include "SkColorPriv.h"
|
| #include "SkNx.h"
|
| #include "SkReadBuffer.h"
|
| @@ -35,10 +34,10 @@ static void transpose_to_pmorder(float dst[20], const float src[20]) {
|
|
|
| // src is [20] but some compilers won't accept __restrict__ on anything
|
| // but an raw pointer or reference
|
| -void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) {
|
| +void SkColorMatrixFilterRowMajor255::initState(const SkScalar* SK_RESTRICT src) {
|
| transpose_to_pmorder(fTranspose, src);
|
|
|
| - const float* array = fMatrix.fMat;
|
| + const float* array = fMatrix;
|
|
|
| // check if we have to munge Alpha
|
| bool changesAlpha = (array[15] || array[16] || array[17] || (array[18] - 1) || array[19]);
|
| @@ -54,16 +53,12 @@ void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) {
|
| - this->initState(cm.fMat);
|
| -}
|
| -
|
| -SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) {
|
| - memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar));
|
| +SkColorMatrixFilterRowMajor255::SkColorMatrixFilterRowMajor255(const SkScalar array[20]) {
|
| + memcpy(fMatrix, array, 20 * sizeof(SkScalar));
|
| this->initState(array);
|
| }
|
|
|
| -uint32_t SkColorMatrixFilter::getFlags() const {
|
| +uint32_t SkColorMatrixFilterRowMajor255::getFlags() const {
|
| return this->INHERITED::getFlags() | fFlags;
|
| }
|
|
|
| @@ -135,7 +130,7 @@ struct SkPMColorAdaptor {
|
| return SkNx_cast<float>(Sk4b::Load(&c)) * Sk4f(1.0f/255);
|
| }
|
| };
|
| -void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
|
| +void SkColorMatrixFilterRowMajor255::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
|
| filter_span<SkPMColorAdaptor>(fTranspose, src, count, dst);
|
| }
|
|
|
| @@ -149,38 +144,92 @@ struct SkPM4fAdaptor {
|
| return Sk4f::Load(&c);
|
| }
|
| };
|
| -void SkColorMatrixFilter::filterSpan4f(const SkPM4f src[], int count, SkPM4f dst[]) const {
|
| +void SkColorMatrixFilterRowMajor255::filterSpan4f(const SkPM4f src[], int count, SkPM4f dst[]) const {
|
| filter_span<SkPM4fAdaptor>(fTranspose, src, count, dst);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -void SkColorMatrixFilter::flatten(SkWriteBuffer& buffer) const {
|
| - SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20);
|
| - buffer.writeScalarArray(fMatrix.fMat, 20);
|
| +void SkColorMatrixFilterRowMajor255::flatten(SkWriteBuffer& buffer) const {
|
| + SkASSERT(sizeof(fMatrix)/sizeof(SkScalar) == 20);
|
| + buffer.writeScalarArray(fMatrix, 20);
|
| }
|
|
|
| -SkFlattenable* SkColorMatrixFilter::CreateProc(SkReadBuffer& buffer) {
|
| - SkColorMatrix matrix;
|
| - if (buffer.readScalarArray(matrix.fMat, 20)) {
|
| - return Create(matrix);
|
| +SkFlattenable* SkColorMatrixFilterRowMajor255::CreateProc(SkReadBuffer& buffer) {
|
| + SkScalar matrix[20];
|
| + if (buffer.readScalarArray(matrix, 20)) {
|
| + return new SkColorMatrixFilterRowMajor255(matrix);
|
| }
|
| return nullptr;
|
| }
|
|
|
| -bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const {
|
| +bool SkColorMatrixFilterRowMajor255::asColorMatrix(SkScalar matrix[20]) const {
|
| if (matrix) {
|
| - memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar));
|
| + memcpy(matrix, fMatrix, 20 * sizeof(SkScalar));
|
| }
|
| return true;
|
| }
|
|
|
| -SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter) const {
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// This code was duplicated from src/effects/SkColorMatrixc.cpp in order to be used in core.
|
| +//////
|
| +
|
| +// To detect if we need to apply clamping after applying a matrix, we check if
|
| +// any output component might go outside of [0, 255] for any combination of
|
| +// input components in [0..255].
|
| +// Each output component is an affine transformation of the input component, so
|
| +// the minimum and maximum values are for any combination of minimum or maximum
|
| +// values of input components (i.e. 0 or 255).
|
| +// E.g. if R' = x*R + y*G + z*B + w*A + t
|
| +// Then the maximum value will be for R=255 if x>0 or R=0 if x<0, and the
|
| +// minimum value will be for R=0 if x>0 or R=255 if x<0.
|
| +// Same goes for all components.
|
| +static bool component_needs_clamping(const SkScalar row[5]) {
|
| + SkScalar maxValue = row[4] / 255;
|
| + SkScalar minValue = row[4] / 255;
|
| + for (int i = 0; i < 4; ++i) {
|
| + if (row[i] > 0)
|
| + maxValue += row[i];
|
| + else
|
| + minValue += row[i];
|
| + }
|
| + return (maxValue > 1) || (minValue < 0);
|
| +}
|
| +
|
| +static bool needs_clamping(const SkScalar matrix[20]) {
|
| + return component_needs_clamping(matrix)
|
| + || component_needs_clamping(matrix+5)
|
| + || component_needs_clamping(matrix+10)
|
| + || component_needs_clamping(matrix+15);
|
| +}
|
| +
|
| +static void set_concat(SkScalar result[20], const SkScalar outer[20], const SkScalar inner[20]) {
|
| + int index = 0;
|
| + for (int j = 0; j < 20; j += 5) {
|
| + for (int i = 0; i < 4; i++) {
|
| + result[index++] = outer[j + 0] * inner[i + 0] +
|
| + outer[j + 1] * inner[i + 5] +
|
| + outer[j + 2] * inner[i + 10] +
|
| + outer[j + 3] * inner[i + 15];
|
| + }
|
| + result[index++] = outer[j + 0] * inner[4] +
|
| + outer[j + 1] * inner[9] +
|
| + outer[j + 2] * inner[14] +
|
| + outer[j + 3] * inner[19] +
|
| + outer[j + 4];
|
| + }
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// End duplication
|
| +//////
|
| +
|
| +SkColorFilter* SkColorMatrixFilterRowMajor255::newComposed(const SkColorFilter* innerFilter) const {
|
| SkScalar innerMatrix[20];
|
| - if (innerFilter->asColorMatrix(innerMatrix) && !SkColorMatrix::NeedsClamping(innerMatrix)) {
|
| + if (innerFilter->asColorMatrix(innerMatrix) && !needs_clamping(innerMatrix)) {
|
| SkScalar concat[20];
|
| - SkColorMatrix::SetConcat(concat, fMatrix.fMat, innerMatrix);
|
| - return SkColorMatrixFilter::Create(concat);
|
| + set_concat(concat, fMatrix, innerMatrix);
|
| + return new SkColorMatrixFilterRowMajor255(concat);
|
| }
|
| return nullptr;
|
| }
|
| @@ -195,7 +244,7 @@ SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter
|
|
|
| class ColorMatrixEffect : public GrFragmentProcessor {
|
| public:
|
| - static const GrFragmentProcessor* Create(const SkColorMatrix& matrix) {
|
| + static const GrFragmentProcessor* Create(const SkScalar matrix[20]) {
|
| return new ColorMatrixEffect(matrix);
|
| }
|
|
|
| @@ -242,7 +291,7 @@ public:
|
| virtual void onSetData(const GrGLSLProgramDataManager& uniManager,
|
| const GrProcessor& proc) override {
|
| const ColorMatrixEffect& cme = proc.cast<ColorMatrixEffect>();
|
| - const float* m = cme.fMatrix.fMat;
|
| + const float* m = cme.fMatrix;
|
| // The GL matrix is transposed from SkColorMatrix.
|
| float mt[] = {
|
| m[0], m[5], m[10], m[15],
|
| @@ -266,7 +315,8 @@ public:
|
| };
|
|
|
| private:
|
| - ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {
|
| + ColorMatrixEffect(const SkScalar matrix[20]) {
|
| + memcpy(fMatrix, matrix, sizeof(SkScalar) * 20);
|
| this->initClassID<ColorMatrixEffect>();
|
| }
|
|
|
| @@ -281,7 +331,7 @@ private:
|
|
|
| bool onIsEqual(const GrFragmentProcessor& s) const override {
|
| const ColorMatrixEffect& cme = s.cast<ColorMatrixEffect>();
|
| - return cme.fMatrix == fMatrix;
|
| + return 0 == memcmp(fMatrix, cme.fMatrix, sizeof(fMatrix));
|
| }
|
|
|
| void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
|
| @@ -309,17 +359,17 @@ private:
|
| for (int i = 0; i < 4; ++i) {
|
| // If any relevant component of the color to be passed through the matrix is non-const
|
| // then we can't know the final result.
|
| - if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
|
| + if (0 != fMatrix[kAlphaRowStartIdx + i]) {
|
| if (!(inout->validFlags() & kRGBAFlags[i])) {
|
| inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
|
| return;
|
| } else {
|
| uint32_t component = (inout->color() >> kShifts[i]) & 0xFF;
|
| - outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
|
| + outputA += fMatrix[kAlphaRowStartIdx + i] * component;
|
| }
|
| }
|
| }
|
| - outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
|
| + outputA += fMatrix[kAlphaRowTranslateIdx];
|
| // We pin the color to [0,1]. This would happen to the *final* color output from the frag
|
| // shader but currently the effect does not pin its own output. So in the case of over/
|
| // underflow this may deviate from the actual result. Maybe the effect should pin its
|
| @@ -329,7 +379,7 @@ private:
|
| GrInvariantOutput::kWill_ReadInput);
|
| }
|
|
|
| - SkColorMatrix fMatrix;
|
| + SkScalar fMatrix[20];
|
|
|
| typedef GrFragmentProcessor INHERITED;
|
| };
|
| @@ -337,26 +387,26 @@ private:
|
| GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect);
|
|
|
| const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d) {
|
| - SkColorMatrix colorMatrix;
|
| - for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) {
|
| - colorMatrix.fMat[i] = d->fRandom->nextSScalar1();
|
| + SkScalar colorMatrix[20];
|
| + for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix); ++i) {
|
| + colorMatrix[i] = d->fRandom->nextSScalar1();
|
| }
|
| return ColorMatrixEffect::Create(colorMatrix);
|
| }
|
|
|
| -const GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*) const {
|
| +const GrFragmentProcessor* SkColorMatrixFilterRowMajor255::asFragmentProcessor(GrContext*) const {
|
| return ColorMatrixEffect::Create(fMatrix);
|
| }
|
|
|
| #endif
|
|
|
| #ifndef SK_IGNORE_TO_STRING
|
| -void SkColorMatrixFilter::toString(SkString* str) const {
|
| - str->append("SkColorMatrixFilter: ");
|
| +void SkColorMatrixFilterRowMajor255::toString(SkString* str) const {
|
| + str->append("SkColorMatrixFilterRowMajor255: ");
|
|
|
| str->append("matrix: (");
|
| for (int i = 0; i < 20; ++i) {
|
| - str->appendScalar(fMatrix.fMat[i]);
|
| + str->appendScalar(fMatrix[i]);
|
| if (i < 19) {
|
| str->append(", ");
|
| }
|
| @@ -367,24 +417,6 @@ void SkColorMatrixFilter::toString(SkString* str) const {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
|
|
| -static SkScalar byte_to_scale(U8CPU byte) {
|
| - if (0xFF == byte) {
|
| - // want to get this exact
|
| - return 1;
|
| - } else {
|
| - return byte * 0.00392156862745f;
|
| - }
|
| -}
|
| -
|
| -SkColorFilter* SkColorMatrixFilter::CreateLightingFilter(SkColor mul, SkColor add) {
|
| - SkColorMatrix matrix;
|
| - matrix.setScale(byte_to_scale(SkColorGetR(mul)),
|
| - byte_to_scale(SkColorGetG(mul)),
|
| - byte_to_scale(SkColorGetB(mul)),
|
| - 1);
|
| - matrix.postTranslate(SkIntToScalar(SkColorGetR(add)),
|
| - SkIntToScalar(SkColorGetG(add)),
|
| - SkIntToScalar(SkColorGetB(add)),
|
| - 0);
|
| - return SkColorMatrixFilter::Create(matrix);
|
| +SkColorFilter* SkColorFilter::CreateMatrixFilterRowMajor255(const SkScalar array[20]) {
|
| + return new SkColorMatrixFilterRowMajor255(array);
|
| }
|
|
|