1 /*
2 * Copyright 2011 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 "include/core/SkRefCnt.h"
9 #include "include/core/SkString.h"
10 #include "include/core/SkUnPreMultiply.h"
11 #include "include/effects/SkColorMatrix.h"
12 #include "include/private/SkColorData.h"
13 #include "include/private/SkNx.h"
14 #include "src/core/SkColorFilter_Matrix.h"
15 #include "src/core/SkRasterPipeline.h"
16 #include "src/core/SkReadBuffer.h"
17 #include "src/core/SkVM.h"
18 #include "src/core/SkWriteBuffer.h"
19
ComputeFlags(const float matrix[20])20 static uint16_t ComputeFlags(const float matrix[20]) {
21 const float* srcA = matrix + 15;
22
23 return SkScalarNearlyZero (srcA[0])
24 && SkScalarNearlyZero (srcA[1])
25 && SkScalarNearlyZero (srcA[2])
26 && SkScalarNearlyEqual(srcA[3], 1)
27 && SkScalarNearlyZero (srcA[4])
28 ? SkColorFilter::kAlphaUnchanged_Flag : 0;
29 }
30
SkColorFilter_Matrix(const float array[20],Domain domain)31 SkColorFilter_Matrix::SkColorFilter_Matrix(const float array[20], Domain domain)
32 : fFlags(ComputeFlags(array))
33 , fDomain(domain) {
34 memcpy(fMatrix, array, 20 * sizeof(float));
35 }
36
getFlags() const37 uint32_t SkColorFilter_Matrix::getFlags() const {
38 return this->INHERITED::getFlags() | fFlags;
39 }
40
flatten(SkWriteBuffer & buffer) const41 void SkColorFilter_Matrix::flatten(SkWriteBuffer& buffer) const {
42 SkASSERT(sizeof(fMatrix)/sizeof(float) == 20);
43 buffer.writeScalarArray(fMatrix, 20);
44
45 // RGBA flag
46 buffer.writeBool(fDomain == Domain::kRGBA);
47 }
48
CreateProc(SkReadBuffer & buffer)49 sk_sp<SkFlattenable> SkColorFilter_Matrix::CreateProc(SkReadBuffer& buffer) {
50 float matrix[20];
51 if (!buffer.readScalarArray(matrix, 20)) {
52 return nullptr;
53 }
54
55 auto is_rgba = buffer.isVersionLT(SkPicturePriv::kMatrixColorFilterDomain_Version) ||
56 buffer.readBool();
57 return is_rgba ? SkColorFilters::Matrix(matrix)
58 : SkColorFilters::HSLAMatrix(matrix);
59 }
60
onAsAColorMatrix(float matrix[20]) const61 bool SkColorFilter_Matrix::onAsAColorMatrix(float matrix[20]) const {
62 if (matrix) {
63 memcpy(matrix, fMatrix, 20 * sizeof(float));
64 }
65 return true;
66 }
67
onAppendStages(const SkStageRec & rec,bool shaderIsOpaque) const68 bool SkColorFilter_Matrix::onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const {
69 const bool willStayOpaque = shaderIsOpaque && (fFlags & kAlphaUnchanged_Flag),
70 hsla = fDomain == Domain::kHSLA;
71
72 SkRasterPipeline* p = rec.fPipeline;
73 if (!shaderIsOpaque) { p->append(SkRasterPipeline::unpremul); }
74 if ( hsla) { p->append(SkRasterPipeline::rgb_to_hsl); }
75 if ( true) { p->append(SkRasterPipeline::matrix_4x5, fMatrix); }
76 if ( hsla) { p->append(SkRasterPipeline::hsl_to_rgb); }
77 if ( true) { p->append(SkRasterPipeline::clamp_0); }
78 if ( true) { p->append(SkRasterPipeline::clamp_1); }
79 if (!willStayOpaque) { p->append(SkRasterPipeline::premul); }
80 return true;
81 }
82
onProgram(skvm::Builder * p,SkColorSpace *,skvm::Uniforms * uniforms,SkArenaAlloc *,skvm::F32 * r,skvm::F32 * g,skvm::F32 * b,skvm::F32 * a) const83 bool SkColorFilter_Matrix::onProgram(skvm::Builder* p,
84 SkColorSpace* /*dstCS*/,
85 skvm::Uniforms* uniforms, SkArenaAlloc*,
86 skvm::F32* r, skvm::F32* g, skvm::F32* b, skvm::F32* a) const {
87 // TODO: specialize generated code on the 0/1 values of fMatrix?
88 if (fDomain == Domain::kRGBA) {
89 p->unpremul(r,g,b,*a);
90
91 auto m = [&](int i) { return p->uniformF(uniforms->pushF(fMatrix[i])); };
92
93 skvm::F32 rgba[4];
94 for (int j = 0; j < 4; j++) {
95 rgba[j] = m(4+j*5);
96 rgba[j] = p->mad(m(3+j*5), *a, rgba[j]);
97 rgba[j] = p->mad(m(2+j*5), *b, rgba[j]);
98 rgba[j] = p->mad(m(1+j*5), *g, rgba[j]);
99 rgba[j] = p->mad(m(0+j*5), *r, rgba[j]);
100 }
101 *r = rgba[0];
102 *g = rgba[1];
103 *b = rgba[2];
104 *a = rgba[3];
105
106 p->premul(r,g,b,*a);
107 return true;
108 }
109 return false;
110 }
111
112 #if SK_SUPPORT_GPU
113 #include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
114 #include "src/gpu/effects/generated/GrHSLToRGBFilterEffect.h"
115 #include "src/gpu/effects/generated/GrRGBToHSLFilterEffect.h"
asFragmentProcessor(GrRecordingContext *,const GrColorInfo &) const116 std::unique_ptr<GrFragmentProcessor> SkColorFilter_Matrix::asFragmentProcessor(
117 GrRecordingContext*, const GrColorInfo&) const {
118 switch (fDomain) {
119 case Domain::kRGBA:
120 return GrColorMatrixFragmentProcessor::Make(fMatrix,
121 /* premulInput = */ true,
122 /* clampRGBOutput = */ true,
123 /* premulOutput = */ true);
124 case Domain::kHSLA: {
125 std::unique_ptr<GrFragmentProcessor> series[] = {
126 GrRGBToHSLFilterEffect::Make(),
127 GrColorMatrixFragmentProcessor::Make(fMatrix,
128 /* premulInput = */ false,
129 /* clampRGBOutput = */ false,
130 /* premulOutput = */ false),
131 GrHSLToRGBFilterEffect::Make(),
132 };
133 return GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series));
134 }
135 }
136
137 SkUNREACHABLE;
138 }
139
140 #endif
141
142 ///////////////////////////////////////////////////////////////////////////////
143
MakeMatrix(const float array[20],SkColorFilter_Matrix::Domain domain)144 static sk_sp<SkColorFilter> MakeMatrix(const float array[20],
145 SkColorFilter_Matrix::Domain domain) {
146 return sk_floats_are_finite(array, 20)
147 ? sk_make_sp<SkColorFilter_Matrix>(array, domain)
148 : nullptr;
149 }
150
Matrix(const float array[20])151 sk_sp<SkColorFilter> SkColorFilters::Matrix(const float array[20]) {
152 return MakeMatrix(array, SkColorFilter_Matrix::Domain::kRGBA);
153 }
154
Matrix(const SkColorMatrix & cm)155 sk_sp<SkColorFilter> SkColorFilters::Matrix(const SkColorMatrix& cm) {
156 return MakeMatrix(cm.fMat.data(), SkColorFilter_Matrix::Domain::kRGBA);
157 }
158
HSLAMatrix(const float array[20])159 sk_sp<SkColorFilter> SkColorFilters::HSLAMatrix(const float array[20]) {
160 return MakeMatrix(array, SkColorFilter_Matrix::Domain::kHSLA);
161 }
162
RegisterFlattenables()163 void SkColorFilter_Matrix::RegisterFlattenables() {
164 SK_REGISTER_FLATTENABLE(SkColorFilter_Matrix);
165
166 // This subclass was removed 4/2019
167 SkFlattenable::Register("SkColorMatrixFilterRowMajor255",
168 [](SkReadBuffer& buffer) -> sk_sp<SkFlattenable> {
169 float matrix[20];
170 if (buffer.readScalarArray(matrix, 20)) {
171 matrix[ 4] *= (1.0f/255);
172 matrix[ 9] *= (1.0f/255);
173 matrix[14] *= (1.0f/255);
174 matrix[19] *= (1.0f/255);
175 return SkColorFilters::Matrix(matrix);
176 }
177 return nullptr;
178 });
179 }
180