Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: src/effects/SkColorMatrixFilter.cpp

Issue 1648933002: Move SkColorMatrixFilter implementation to core. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: add back newComposed override Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkColorMatrixFilter.h" 8 #include "SkColorMatrixFilter.h"
9 #include "SkColorMatrix.h"
10 #include "SkColorPriv.h"
11 #include "SkNx.h"
12 #include "SkReadBuffer.h"
13 #include "SkWriteBuffer.h"
14 #include "SkUnPreMultiply.h"
15 #include "SkString.h"
16
17 #define SK_PMORDER_INDEX_A (SK_A32_SHIFT / 8)
18 #define SK_PMORDER_INDEX_R (SK_R32_SHIFT / 8)
19 #define SK_PMORDER_INDEX_G (SK_G32_SHIFT / 8)
20 #define SK_PMORDER_INDEX_B (SK_B32_SHIFT / 8)
21
22 static void transpose_to_pmorder(float dst[20], const float src[20]) {
23 const float* srcR = src + 0;
24 const float* srcG = src + 5;
25 const float* srcB = src + 10;
26 const float* srcA = src + 15;
27
28 for (int i = 0; i < 20; i += 4) {
29 dst[i + SK_PMORDER_INDEX_A] = *srcA++;
30 dst[i + SK_PMORDER_INDEX_R] = *srcR++;
31 dst[i + SK_PMORDER_INDEX_G] = *srcG++;
32 dst[i + SK_PMORDER_INDEX_B] = *srcB++;
33 }
34 }
35
36 // src is [20] but some compilers won't accept __restrict__ on anything
37 // but an raw pointer or reference
38 void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) {
39 transpose_to_pmorder(fTranspose, src);
40
41 const float* array = fMatrix.fMat;
42
43 // check if we have to munge Alpha
44 bool changesAlpha = (array[15] || array[16] || array[17] || (array[18] - 1) || array[19]);
45 bool usesAlpha = (array[3] || array[8] || array[13]);
46
47 if (changesAlpha || usesAlpha) {
48 fFlags = changesAlpha ? 0 : kAlphaUnchanged_Flag;
49 } else {
50 fFlags = kAlphaUnchanged_Flag;
51 }
52 fFlags |= kSupports4f_Flag;
53 }
54
55 ///////////////////////////////////////////////////////////////////////////////
56
57 SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) {
58 this->initState(cm.fMat);
59 }
60
61 SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) {
62 memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar));
63 this->initState(array);
64 }
65
66 uint32_t SkColorMatrixFilter::getFlags() const {
67 return this->INHERITED::getFlags() | fFlags;
68 }
69
70 static Sk4f scale_rgb(float scale) {
71 static_assert(SkPM4f::A == 3, "Alpha is lane 3");
72 return Sk4f(scale, scale, scale, 1);
73 }
74
75 static Sk4f premul(const Sk4f& x) {
76 return x * scale_rgb(x.kth<SkPM4f::A>());
77 }
78
79 static Sk4f unpremul(const Sk4f& x) {
80 return x * scale_rgb(1 / x.kth<SkPM4f::A>()); // TODO: fast/approx invert?
81 }
82
83 static Sk4f clamp_0_1(const Sk4f& x) {
84 return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0));
85 }
86
87 static SkPMColor round(const Sk4f& x) {
88 SkPMColor c;
89 SkNx_cast<uint8_t>(x * Sk4f(255) + Sk4f(0.5f)).store(&c);
90 return c;
91 }
92
93 template <typename Adaptor, typename T>
94 void filter_span(const float array[], const T src[], int count, T dst[]) {
95 // c0-c3 are already in [0,1].
96 const Sk4f c0 = Sk4f::Load(array + 0);
97 const Sk4f c1 = Sk4f::Load(array + 4);
98 const Sk4f c2 = Sk4f::Load(array + 8);
99 const Sk4f c3 = Sk4f::Load(array + 12);
100 // c4 (the translate vector) is in [0, 255]. Bring it back to [0,1].
101 const Sk4f c4 = Sk4f::Load(array + 16)*Sk4f(1.0f/255);
102
103 // todo: we could cache this in the constructor...
104 T matrix_translate_pmcolor = Adaptor::From4f(premul(clamp_0_1(c4)));
105
106 for (int i = 0; i < count; i++) {
107 Sk4f srcf = Adaptor::To4f(src[i]);
108 float srcA = srcf.kth<SkPM4f::A>();
109
110 if (0 == srcA) {
111 dst[i] = matrix_translate_pmcolor;
112 continue;
113 }
114 if (1 != srcA) {
115 srcf = unpremul(srcf);
116 }
117
118 Sk4f r4 = SkNx_dup<SK_R32_SHIFT/8>(srcf);
119 Sk4f g4 = SkNx_dup<SK_G32_SHIFT/8>(srcf);
120 Sk4f b4 = SkNx_dup<SK_B32_SHIFT/8>(srcf);
121 Sk4f a4 = SkNx_dup<SK_A32_SHIFT/8>(srcf);
122
123 // apply matrix
124 Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4;
125
126 dst[i] = Adaptor::From4f(premul(clamp_0_1(dst4)));
127 }
128 }
129
130 struct SkPMColorAdaptor {
131 static SkPMColor From4f(const Sk4f& c4) {
132 return round(c4);
133 }
134 static Sk4f To4f(SkPMColor c) {
135 return SkNx_cast<float>(Sk4b::Load(&c)) * Sk4f(1.0f/255);
136 }
137 };
138 void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
139 filter_span<SkPMColorAdaptor>(fTranspose, src, count, dst);
140 }
141
142 struct SkPM4fAdaptor {
143 static SkPM4f From4f(const Sk4f& c4) {
144 SkPM4f c;
145 c4.store(&c);
146 return c;
147 }
148 static Sk4f To4f(const SkPM4f& c) {
149 return Sk4f::Load(&c);
150 }
151 };
152 void SkColorMatrixFilter::filterSpan4f(const SkPM4f src[], int count, SkPM4f dst []) const {
153 filter_span<SkPM4fAdaptor>(fTranspose, src, count, dst);
154 }
155
156 ///////////////////////////////////////////////////////////////////////////////
157
158 void SkColorMatrixFilter::flatten(SkWriteBuffer& buffer) const {
159 SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20);
160 buffer.writeScalarArray(fMatrix.fMat, 20);
161 }
162
163 SkFlattenable* SkColorMatrixFilter::CreateProc(SkReadBuffer& buffer) {
164 SkColorMatrix matrix;
165 if (buffer.readScalarArray(matrix.fMat, 20)) {
166 return Create(matrix);
167 }
168 return nullptr;
169 }
170
171 bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const {
172 if (matrix) {
173 memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar));
174 }
175 return true;
176 }
177
178 SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter ) const {
179 SkScalar innerMatrix[20];
180 if (innerFilter->asColorMatrix(innerMatrix) && !SkColorMatrix::NeedsClamping (innerMatrix)) {
181 SkScalar concat[20];
182 SkColorMatrix::SetConcat(concat, fMatrix.fMat, innerMatrix);
183 return SkColorMatrixFilter::Create(concat);
184 }
185 return nullptr;
186 }
187
188 #if SK_SUPPORT_GPU
189 #include "GrFragmentProcessor.h"
190 #include "GrInvariantOutput.h"
191 #include "glsl/GrGLSLFragmentProcessor.h"
192 #include "glsl/GrGLSLFragmentShaderBuilder.h"
193 #include "glsl/GrGLSLProgramDataManager.h"
194 #include "glsl/GrGLSLUniformHandler.h"
195
196 class ColorMatrixEffect : public GrFragmentProcessor {
197 public:
198 static const GrFragmentProcessor* Create(const SkColorMatrix& matrix) {
199 return new ColorMatrixEffect(matrix);
200 }
201
202 const char* name() const override { return "Color Matrix"; }
203
204 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
205
206 class GLSLProcessor : public GrGLSLFragmentProcessor {
207 public:
208 // this class always generates the same code.
209 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKey Builder* b) {}
210
211 GLSLProcessor(const GrProcessor&) {}
212
213 virtual void emitCode(EmitArgs& args) override {
214 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
215 fMatrixHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFr agment_Visibility,
216 kMat44f_GrSLType, kDefaul t_GrSLPrecision,
217 "ColorMatrix");
218 fVectorHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFr agment_Visibility,
219 kVec4f_GrSLType, kDefault _GrSLPrecision,
220 "ColorMatrixVector");
221
222 if (nullptr == args.fInputColor) {
223 // could optimize this case, but we aren't for now.
224 args.fInputColor = "vec4(1)";
225 }
226 GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
227 // The max() is to guard against 0 / 0 during unpremul when the inco ming color is
228 // transparent black.
229 fragBuilder->codeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001); \n",
230 args.fInputColor);
231 fragBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, no nZeroAlpha) + %s;\n",
232 args.fOutputColor,
233 uniformHandler->getUniformCStr(fMatrixHandl e),
234 args.fInputColor,
235 uniformHandler->getUniformCStr(fVectorHandl e));
236 fragBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n",
237 args.fOutputColor, args.fOutputColor);
238 fragBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", args.fOutputColor, a rgs.fOutputColor);
239 }
240
241 protected:
242 virtual void onSetData(const GrGLSLProgramDataManager& uniManager,
243 const GrProcessor& proc) override {
244 const ColorMatrixEffect& cme = proc.cast<ColorMatrixEffect>();
245 const float* m = cme.fMatrix.fMat;
246 // The GL matrix is transposed from SkColorMatrix.
247 float mt[] = {
248 m[0], m[5], m[10], m[15],
249 m[1], m[6], m[11], m[16],
250 m[2], m[7], m[12], m[17],
251 m[3], m[8], m[13], m[18],
252 };
253 static const float kScale = 1.0f / 255.0f;
254 float vec[] = {
255 m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale,
256 };
257 uniManager.setMatrix4fv(fMatrixHandle, 1, mt);
258 uniManager.set4fv(fVectorHandle, 1, vec);
259 }
260
261 private:
262 GrGLSLProgramDataManager::UniformHandle fMatrixHandle;
263 GrGLSLProgramDataManager::UniformHandle fVectorHandle;
264
265 typedef GrGLSLFragmentProcessor INHERITED;
266 };
267
268 private:
269 ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {
270 this->initClassID<ColorMatrixEffect>();
271 }
272
273 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
274 return new GLSLProcessor(*this);
275 }
276
277 virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
278 GrProcessorKeyBuilder* b) const override {
279 GLSLProcessor::GenKey(*this, caps, b);
280 }
281
282 bool onIsEqual(const GrFragmentProcessor& s) const override {
283 const ColorMatrixEffect& cme = s.cast<ColorMatrixEffect>();
284 return cme.fMatrix == fMatrix;
285 }
286
287 void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
288 // We only bother to check whether the alpha channel will be constant. I f SkColorMatrix had
289 // type flags it might be worth checking the other components.
290
291 // The matrix is defined such the 4th row determines the output alpha. T he first four
292 // columns of that row multiply the input r, g, b, and a, respectively, and the last column
293 // is the "translation".
294 static const uint32_t kRGBAFlags[] = {
295 kR_GrColorComponentFlag,
296 kG_GrColorComponentFlag,
297 kB_GrColorComponentFlag,
298 kA_GrColorComponentFlag
299 };
300 static const int kShifts[] = {
301 GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
302 };
303 enum {
304 kAlphaRowStartIdx = 15,
305 kAlphaRowTranslateIdx = 19,
306 };
307
308 SkScalar outputA = 0;
309 for (int i = 0; i < 4; ++i) {
310 // If any relevant component of the color to be passed through the m atrix is non-const
311 // then we can't know the final result.
312 if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
313 if (!(inout->validFlags() & kRGBAFlags[i])) {
314 inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
315 return;
316 } else {
317 uint32_t component = (inout->color() >> kShifts[i]) & 0xFF;
318 outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
319 }
320 }
321 }
322 outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
323 // We pin the color to [0,1]. This would happen to the *final* color out put from the frag
324 // shader but currently the effect does not pin its own output. So in th e case of over/
325 // underflow this may deviate from the actual result. Maybe the effect s hould pin its
326 // result if the matrix could over/underflow for any component?
327 inout->setToOther(kA_GrColorComponentFlag,
328 static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A,
329 GrInvariantOutput::kWill_ReadInput);
330 }
331
332 SkColorMatrix fMatrix;
333
334 typedef GrFragmentProcessor INHERITED;
335 };
336
337 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect);
338
339 const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d) {
340 SkColorMatrix colorMatrix;
341 for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) {
342 colorMatrix.fMat[i] = d->fRandom->nextSScalar1();
343 }
344 return ColorMatrixEffect::Create(colorMatrix);
345 }
346
347 const GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*) const {
348 return ColorMatrixEffect::Create(fMatrix);
349 }
350
351 #endif
352
353 #ifndef SK_IGNORE_TO_STRING
354 void SkColorMatrixFilter::toString(SkString* str) const {
355 str->append("SkColorMatrixFilter: ");
356
357 str->append("matrix: (");
358 for (int i = 0; i < 20; ++i) {
359 str->appendScalar(fMatrix.fMat[i]);
360 if (i < 19) {
361 str->append(", ");
362 }
363 }
364 str->append(")");
365 }
366 #endif
367
368 ///////////////////////////////////////////////////////////////////////////////
369 9
370 static SkScalar byte_to_scale(U8CPU byte) { 10 static SkScalar byte_to_scale(U8CPU byte) {
371 if (0xFF == byte) { 11 if (0xFF == byte) {
372 // want to get this exact 12 // want to get this exact
373 return 1; 13 return 1;
374 } else { 14 } else {
375 return byte * 0.00392156862745f; 15 return byte * 0.00392156862745f;
376 } 16 }
377 } 17 }
378 18
379 SkColorFilter* SkColorMatrixFilter::CreateLightingFilter(SkColor mul, SkColor ad d) { 19 SkColorFilter* SkColorMatrixFilter::CreateLightingFilter(SkColor mul, SkColor ad d) {
380 SkColorMatrix matrix; 20 SkColorMatrix matrix;
381 matrix.setScale(byte_to_scale(SkColorGetR(mul)), 21 matrix.setScale(byte_to_scale(SkColorGetR(mul)),
382 byte_to_scale(SkColorGetG(mul)), 22 byte_to_scale(SkColorGetG(mul)),
383 byte_to_scale(SkColorGetB(mul)), 23 byte_to_scale(SkColorGetB(mul)),
384 1); 24 1);
385 matrix.postTranslate(SkIntToScalar(SkColorGetR(add)), 25 matrix.postTranslate(SkIntToScalar(SkColorGetR(add)),
386 SkIntToScalar(SkColorGetG(add)), 26 SkIntToScalar(SkColorGetG(add)),
387 SkIntToScalar(SkColorGetB(add)), 27 SkIntToScalar(SkColorGetB(add)),
388 0); 28 0);
389 return SkColorMatrixFilter::Create(matrix); 29 return SkColorMatrixFilter::Create(matrix);
390 } 30 }
OLDNEW
« no previous file with comments | « src/core/SkColorMatrixFilterRowMajor255.cpp ('k') | src/ports/SkGlobalInitialization_default.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698