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); |
} |