• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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