Index: src/effects/SkColorMatrixFilter.cpp |
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp |
index a0878a5044c5c363a74d8132f1cbebcb9da10b52..e122b6ac8e8aef1bed2171dac4173ac7f484c67b 100644 |
--- a/src/effects/SkColorMatrixFilter.cpp |
+++ b/src/effects/SkColorMatrixFilter.cpp |
@@ -6,366 +6,6 @@ |
*/ |
#include "SkColorMatrixFilter.h" |
-#include "SkColorMatrix.h" |
-#include "SkColorPriv.h" |
-#include "SkNx.h" |
-#include "SkReadBuffer.h" |
-#include "SkWriteBuffer.h" |
-#include "SkUnPreMultiply.h" |
-#include "SkString.h" |
- |
-#define SK_PMORDER_INDEX_A (SK_A32_SHIFT / 8) |
-#define SK_PMORDER_INDEX_R (SK_R32_SHIFT / 8) |
-#define SK_PMORDER_INDEX_G (SK_G32_SHIFT / 8) |
-#define SK_PMORDER_INDEX_B (SK_B32_SHIFT / 8) |
- |
-static void transpose_to_pmorder(float dst[20], const float src[20]) { |
- const float* srcR = src + 0; |
- const float* srcG = src + 5; |
- const float* srcB = src + 10; |
- const float* srcA = src + 15; |
- |
- for (int i = 0; i < 20; i += 4) { |
- dst[i + SK_PMORDER_INDEX_A] = *srcA++; |
- dst[i + SK_PMORDER_INDEX_R] = *srcR++; |
- dst[i + SK_PMORDER_INDEX_G] = *srcG++; |
- dst[i + SK_PMORDER_INDEX_B] = *srcB++; |
- } |
-} |
- |
-// 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) { |
- transpose_to_pmorder(fTranspose, src); |
- |
- const float* array = fMatrix.fMat; |
- |
- // check if we have to munge Alpha |
- bool changesAlpha = (array[15] || array[16] || array[17] || (array[18] - 1) || array[19]); |
- bool usesAlpha = (array[3] || array[8] || array[13]); |
- |
- if (changesAlpha || usesAlpha) { |
- fFlags = changesAlpha ? 0 : kAlphaUnchanged_Flag; |
- } else { |
- fFlags = kAlphaUnchanged_Flag; |
- } |
- fFlags |= kSupports4f_Flag; |
-} |
- |
-/////////////////////////////////////////////////////////////////////////////// |
- |
-SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) { |
- this->initState(cm.fMat); |
-} |
- |
-SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) { |
- memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar)); |
- this->initState(array); |
-} |
- |
-uint32_t SkColorMatrixFilter::getFlags() const { |
- return this->INHERITED::getFlags() | fFlags; |
-} |
- |
-static Sk4f scale_rgb(float scale) { |
- static_assert(SkPM4f::A == 3, "Alpha is lane 3"); |
- return Sk4f(scale, scale, scale, 1); |
-} |
- |
-static Sk4f premul(const Sk4f& x) { |
- return x * scale_rgb(x.kth<SkPM4f::A>()); |
-} |
- |
-static Sk4f unpremul(const Sk4f& x) { |
- return x * scale_rgb(1 / x.kth<SkPM4f::A>()); // TODO: fast/approx invert? |
-} |
- |
-static Sk4f clamp_0_1(const Sk4f& x) { |
- return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0)); |
-} |
- |
-static SkPMColor round(const Sk4f& x) { |
- SkPMColor c; |
- SkNx_cast<uint8_t>(x * Sk4f(255) + Sk4f(0.5f)).store(&c); |
- return c; |
-} |
- |
-template <typename Adaptor, typename T> |
-void filter_span(const float array[], const T src[], int count, T dst[]) { |
- // c0-c3 are already in [0,1]. |
- const Sk4f c0 = Sk4f::Load(array + 0); |
- const Sk4f c1 = Sk4f::Load(array + 4); |
- const Sk4f c2 = Sk4f::Load(array + 8); |
- const Sk4f c3 = Sk4f::Load(array + 12); |
- // c4 (the translate vector) is in [0, 255]. Bring it back to [0,1]. |
- const Sk4f c4 = Sk4f::Load(array + 16)*Sk4f(1.0f/255); |
- |
- // todo: we could cache this in the constructor... |
- T matrix_translate_pmcolor = Adaptor::From4f(premul(clamp_0_1(c4))); |
- |
- for (int i = 0; i < count; i++) { |
- Sk4f srcf = Adaptor::To4f(src[i]); |
- float srcA = srcf.kth<SkPM4f::A>(); |
- |
- if (0 == srcA) { |
- dst[i] = matrix_translate_pmcolor; |
- continue; |
- } |
- if (1 != srcA) { |
- srcf = unpremul(srcf); |
- } |
- |
- Sk4f r4 = SkNx_dup<SK_R32_SHIFT/8>(srcf); |
- Sk4f g4 = SkNx_dup<SK_G32_SHIFT/8>(srcf); |
- Sk4f b4 = SkNx_dup<SK_B32_SHIFT/8>(srcf); |
- Sk4f a4 = SkNx_dup<SK_A32_SHIFT/8>(srcf); |
- |
- // apply matrix |
- Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4; |
- |
- dst[i] = Adaptor::From4f(premul(clamp_0_1(dst4))); |
- } |
-} |
- |
-struct SkPMColorAdaptor { |
- static SkPMColor From4f(const Sk4f& c4) { |
- return round(c4); |
- } |
- static Sk4f To4f(SkPMColor c) { |
- return SkNx_cast<float>(Sk4b::Load(&c)) * Sk4f(1.0f/255); |
- } |
-}; |
-void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { |
- filter_span<SkPMColorAdaptor>(fTranspose, src, count, dst); |
-} |
- |
-struct SkPM4fAdaptor { |
- static SkPM4f From4f(const Sk4f& c4) { |
- SkPM4f c; |
- c4.store(&c); |
- return c; |
- } |
- static Sk4f To4f(const SkPM4f& c) { |
- return Sk4f::Load(&c); |
- } |
-}; |
-void SkColorMatrixFilter::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); |
-} |
- |
-SkFlattenable* SkColorMatrixFilter::CreateProc(SkReadBuffer& buffer) { |
- SkColorMatrix matrix; |
- if (buffer.readScalarArray(matrix.fMat, 20)) { |
- return Create(matrix); |
- } |
- return nullptr; |
-} |
- |
-bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const { |
- if (matrix) { |
- memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar)); |
- } |
- return true; |
-} |
- |
-SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter) const { |
- SkScalar innerMatrix[20]; |
- if (innerFilter->asColorMatrix(innerMatrix) && !SkColorMatrix::NeedsClamping(innerMatrix)) { |
- SkScalar concat[20]; |
- SkColorMatrix::SetConcat(concat, fMatrix.fMat, innerMatrix); |
- return SkColorMatrixFilter::Create(concat); |
- } |
- return nullptr; |
-} |
- |
-#if SK_SUPPORT_GPU |
-#include "GrFragmentProcessor.h" |
-#include "GrInvariantOutput.h" |
-#include "glsl/GrGLSLFragmentProcessor.h" |
-#include "glsl/GrGLSLFragmentShaderBuilder.h" |
-#include "glsl/GrGLSLProgramDataManager.h" |
-#include "glsl/GrGLSLUniformHandler.h" |
- |
-class ColorMatrixEffect : public GrFragmentProcessor { |
-public: |
- static const GrFragmentProcessor* Create(const SkColorMatrix& matrix) { |
- return new ColorMatrixEffect(matrix); |
- } |
- |
- const char* name() const override { return "Color Matrix"; } |
- |
- GR_DECLARE_FRAGMENT_PROCESSOR_TEST; |
- |
- class GLSLProcessor : public GrGLSLFragmentProcessor { |
- public: |
- // this class always generates the same code. |
- static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {} |
- |
- GLSLProcessor(const GrProcessor&) {} |
- |
- virtual void emitCode(EmitArgs& args) override { |
- GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
- fMatrixHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, |
- kMat44f_GrSLType, kDefault_GrSLPrecision, |
- "ColorMatrix"); |
- fVectorHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility, |
- kVec4f_GrSLType, kDefault_GrSLPrecision, |
- "ColorMatrixVector"); |
- |
- if (nullptr == args.fInputColor) { |
- // could optimize this case, but we aren't for now. |
- args.fInputColor = "vec4(1)"; |
- } |
- GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder; |
- // The max() is to guard against 0 / 0 during unpremul when the incoming color is |
- // transparent black. |
- fragBuilder->codeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", |
- args.fInputColor); |
- fragBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n", |
- args.fOutputColor, |
- uniformHandler->getUniformCStr(fMatrixHandle), |
- args.fInputColor, |
- uniformHandler->getUniformCStr(fVectorHandle)); |
- fragBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", |
- args.fOutputColor, args.fOutputColor); |
- fragBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor); |
- } |
- |
- protected: |
- virtual void onSetData(const GrGLSLProgramDataManager& uniManager, |
- const GrProcessor& proc) override { |
- const ColorMatrixEffect& cme = proc.cast<ColorMatrixEffect>(); |
- const float* m = cme.fMatrix.fMat; |
- // The GL matrix is transposed from SkColorMatrix. |
- float mt[] = { |
- m[0], m[5], m[10], m[15], |
- m[1], m[6], m[11], m[16], |
- m[2], m[7], m[12], m[17], |
- m[3], m[8], m[13], m[18], |
- }; |
- static const float kScale = 1.0f / 255.0f; |
- float vec[] = { |
- m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale, |
- }; |
- uniManager.setMatrix4fv(fMatrixHandle, 1, mt); |
- uniManager.set4fv(fVectorHandle, 1, vec); |
- } |
- |
- private: |
- GrGLSLProgramDataManager::UniformHandle fMatrixHandle; |
- GrGLSLProgramDataManager::UniformHandle fVectorHandle; |
- |
- typedef GrGLSLFragmentProcessor INHERITED; |
- }; |
- |
-private: |
- ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) { |
- this->initClassID<ColorMatrixEffect>(); |
- } |
- |
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { |
- return new GLSLProcessor(*this); |
- } |
- |
- virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, |
- GrProcessorKeyBuilder* b) const override { |
- GLSLProcessor::GenKey(*this, caps, b); |
- } |
- |
- bool onIsEqual(const GrFragmentProcessor& s) const override { |
- const ColorMatrixEffect& cme = s.cast<ColorMatrixEffect>(); |
- return cme.fMatrix == fMatrix; |
- } |
- |
- void onComputeInvariantOutput(GrInvariantOutput* inout) const override { |
- // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had |
- // type flags it might be worth checking the other components. |
- |
- // The matrix is defined such the 4th row determines the output alpha. The first four |
- // columns of that row multiply the input r, g, b, and a, respectively, and the last column |
- // is the "translation". |
- static const uint32_t kRGBAFlags[] = { |
- kR_GrColorComponentFlag, |
- kG_GrColorComponentFlag, |
- kB_GrColorComponentFlag, |
- kA_GrColorComponentFlag |
- }; |
- static const int kShifts[] = { |
- GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A, |
- }; |
- enum { |
- kAlphaRowStartIdx = 15, |
- kAlphaRowTranslateIdx = 19, |
- }; |
- |
- SkScalar outputA = 0; |
- 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 (!(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.fMat[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 |
- // result if the matrix could over/underflow for any component? |
- inout->setToOther(kA_GrColorComponentFlag, |
- static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A, |
- GrInvariantOutput::kWill_ReadInput); |
- } |
- |
- SkColorMatrix fMatrix; |
- |
- typedef GrFragmentProcessor INHERITED; |
-}; |
- |
-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(); |
- } |
- return ColorMatrixEffect::Create(colorMatrix); |
-} |
- |
-const GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*) const { |
- return ColorMatrixEffect::Create(fMatrix); |
-} |
- |
-#endif |
- |
-#ifndef SK_IGNORE_TO_STRING |
-void SkColorMatrixFilter::toString(SkString* str) const { |
- str->append("SkColorMatrixFilter: "); |
- |
- str->append("matrix: ("); |
- for (int i = 0; i < 20; ++i) { |
- str->appendScalar(fMatrix.fMat[i]); |
- if (i < 19) { |
- str->append(", "); |
- } |
- } |
- str->append(")"); |
-} |
-#endif |
- |
-/////////////////////////////////////////////////////////////////////////////// |
static SkScalar byte_to_scale(U8CPU byte) { |
if (0xFF == byte) { |