Create GLSLUniformHandler class for gpu backend
[platform/upstream/libSkiaSharp.git] / src / effects / SkColorMatrixFilter.cpp
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 "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 static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g,
37                           unsigned b, unsigned a) {
38     return array[0] * r + array[1] * g  + array[2] * b + array[3] * a + array[4];
39 }
40
41 static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g,
42                        unsigned b) {
43     return array[0] * r + array[1] * g  + array[2] * b + array[4];
44 }
45
46 static void General(const SkColorMatrixFilter::State& state,
47                     unsigned r, unsigned g, unsigned b, unsigned a,
48                     int32_t* SK_RESTRICT result) {
49     const int32_t* SK_RESTRICT array = state.fArray;
50     const int shift = state.fShift;
51
52     result[0] = rowmul4(&array[0], r, g, b, a) >> shift;
53     result[1] = rowmul4(&array[5], r, g, b, a) >> shift;
54     result[2] = rowmul4(&array[10], r, g, b, a) >> shift;
55     result[3] = rowmul4(&array[15], r, g, b, a) >> shift;
56 }
57
58 static void General16(const SkColorMatrixFilter::State& state,
59                       unsigned r, unsigned g, unsigned b, unsigned a,
60                       int32_t* SK_RESTRICT result) {
61     const int32_t* SK_RESTRICT array = state.fArray;
62
63     result[0] = rowmul4(&array[0], r, g, b, a) >> 16;
64     result[1] = rowmul4(&array[5], r, g, b, a) >> 16;
65     result[2] = rowmul4(&array[10], r, g, b, a) >> 16;
66     result[3] = rowmul4(&array[15], r, g, b, a) >> 16;
67 }
68
69 static void AffineAdd(const SkColorMatrixFilter::State& state,
70                       unsigned r, unsigned g, unsigned b, unsigned a,
71                       int32_t* SK_RESTRICT result) {
72     const int32_t* SK_RESTRICT array = state.fArray;
73     const int shift = state.fShift;
74
75     result[0] = rowmul3(&array[0], r, g, b) >> shift;
76     result[1] = rowmul3(&array[5], r, g, b) >> shift;
77     result[2] = rowmul3(&array[10], r, g, b) >> shift;
78     result[3] = a;
79 }
80
81 static void AffineAdd16(const SkColorMatrixFilter::State& state,
82                         unsigned r, unsigned g, unsigned b, unsigned a,
83                         int32_t* SK_RESTRICT result) {
84     const int32_t* SK_RESTRICT array = state.fArray;
85
86     result[0] = rowmul3(&array[0], r, g, b) >> 16;
87     result[1] = rowmul3(&array[5], r, g, b) >> 16;
88     result[2] = rowmul3(&array[10], r, g, b) >> 16;
89     result[3] = a;
90 }
91
92 static void ScaleAdd(const SkColorMatrixFilter::State& state,
93                      unsigned r, unsigned g, unsigned b, unsigned a,
94                      int32_t* SK_RESTRICT result) {
95     const int32_t* SK_RESTRICT array = state.fArray;
96     const int shift = state.fShift;
97
98     // cast to (int) to keep the expression signed for the shift
99     result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> shift;
100     result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> shift;
101     result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> shift;
102     result[3] = a;
103 }
104
105 static void ScaleAdd16(const SkColorMatrixFilter::State& state,
106                        unsigned r, unsigned g, unsigned b, unsigned a,
107                        int32_t* SK_RESTRICT result) {
108     const int32_t* SK_RESTRICT array = state.fArray;
109
110     // cast to (int) to keep the expression signed for the shift
111     result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> 16;
112     result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> 16;
113     result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> 16;
114     result[3] = a;
115 }
116
117 static void Add(const SkColorMatrixFilter::State& state,
118                 unsigned r, unsigned g, unsigned b, unsigned a,
119                 int32_t* SK_RESTRICT result) {
120     const int32_t* SK_RESTRICT array = state.fArray;
121     const int shift = state.fShift;
122
123     result[0] = r + (array[SkColorMatrix::kR_Trans] >> shift);
124     result[1] = g + (array[SkColorMatrix::kG_Trans] >> shift);
125     result[2] = b + (array[SkColorMatrix::kB_Trans] >> shift);
126     result[3] = a;
127 }
128
129 static void Add16(const SkColorMatrixFilter::State& state,
130                   unsigned r, unsigned g, unsigned b, unsigned a,
131                   int32_t* SK_RESTRICT result) {
132     const int32_t* SK_RESTRICT array = state.fArray;
133
134     result[0] = r + (array[SkColorMatrix::kR_Trans] >> 16);
135     result[1] = g + (array[SkColorMatrix::kG_Trans] >> 16);
136     result[2] = b + (array[SkColorMatrix::kB_Trans] >> 16);
137     result[3] = a;
138 }
139
140 // src is [20] but some compilers won't accept __restrict__ on anything
141 // but an raw pointer or reference
142 void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) {
143     transpose_to_pmorder(fTranspose, src);
144
145     int32_t* array = fState.fArray;
146     SkFixed max = 0;
147     for (int i = 0; i < 20; i++) {
148         SkFixed value = SkScalarToFixed(src[i]);
149         array[i] = value;
150         value = SkAbs32(value);
151         max = SkMax32(max, value);
152     }
153
154     /*  All of fArray[] values must fit in 23 bits, to safely allow me to
155         multiply them by 8bit unsigned values, and get a signed answer without
156         overflow. This means clz needs to be 9 or bigger
157     */
158     int bits = SkCLZ(max);
159     int32_t one = SK_Fixed1;
160
161     fState.fShift = 16; // we are starting out as fixed 16.16
162     if (bits < 9) {
163         bits = 9 - bits;
164         fState.fShift -= bits;
165         for (int i = 0; i < 20; i++) {
166             array[i] >>= bits;
167         }
168         one >>= bits;
169     }
170
171     // check if we have to munge Alpha
172     int32_t changesAlpha = (array[15] | array[16] | array[17] |
173                             (array[18] - one) | array[19]);
174     int32_t usesAlpha = (array[3] | array[8] | array[13]);
175     bool shiftIs16 = (16 == fState.fShift);
176
177     if (changesAlpha | usesAlpha) {
178         fProc = shiftIs16 ? General16 : General;
179         fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag;
180     } else {
181         fFlags = SkColorFilter::kAlphaUnchanged_Flag;
182
183         int32_t needsScale = (array[SkColorMatrix::kR_Scale] - one) |
184                              (array[SkColorMatrix::kG_Scale] - one) |
185                              (array[SkColorMatrix::kB_Scale] - one);
186
187         int32_t needs3x3 =  array[1] | array[2] |     // red off-axis
188                             array[5] | array[7] |     // green off-axis
189                             array[10] | array[11];    // blue off-axis
190
191         if (needs3x3) {
192             fProc = shiftIs16 ? AffineAdd16 : AffineAdd;
193         } else if (needsScale) {
194             fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd;
195         } else if (array[SkColorMatrix::kR_Trans] |
196                    array[SkColorMatrix::kG_Trans] |
197                    array[SkColorMatrix::kB_Trans]) {
198             fProc = shiftIs16 ? Add16 : Add;
199         } else {
200             fProc = nullptr;   // identity
201         }
202     }
203
204     /*  preround our add values so we get a rounded shift. We do this after we
205         analyze the array, so we don't miss the case where the caller has zeros
206         which could make us accidentally take the General or Add case.
207     */
208     if (fProc) {
209         int32_t add = 1 << (fState.fShift - 1);
210         array[4] += add;
211         array[9] += add;
212         array[14] += add;
213         array[19] += add;
214     }
215 }
216
217 ///////////////////////////////////////////////////////////////////////////////
218
219 static int32_t pin(int32_t value, int32_t max) {
220     if (value < 0) {
221         value = 0;
222     }
223     if (value > max) {
224         value = max;
225     }
226     return value;
227 }
228
229 SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) {
230     this->initState(cm.fMat);
231 }
232
233 SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) {
234     memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar));
235     this->initState(array);
236 }
237
238 uint32_t SkColorMatrixFilter::getFlags() const {
239     return this->INHERITED::getFlags() | fFlags;
240 }
241
242 static Sk4f scale_rgb(float scale) {
243     static_assert(SK_A32_SHIFT == 24, "Alpha is lane 3");
244     return Sk4f(scale, scale, scale, 1);
245 }
246
247 static Sk4f premul(const Sk4f& x) {
248     return x * scale_rgb(x.kth<SK_A32_SHIFT/8>());
249 }
250
251 static Sk4f unpremul(const Sk4f& x) {
252     return x * scale_rgb(1 / x.kth<SK_A32_SHIFT/8>());  // TODO: fast/approx invert?
253 }
254
255 static Sk4f clamp_0_1(const Sk4f& x) {
256     return Sk4f::Max(Sk4f::Min(x, Sk4f(1)), Sk4f(0));
257 }
258
259 static SkPMColor round(const Sk4f& x) {
260     SkPMColor c;
261     (x * Sk4f(255) + Sk4f(0.5f)).toBytes((uint8_t*)&c);
262     return c;
263 }
264
265 void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
266     Proc proc = fProc;
267     if (nullptr == proc) {
268         if (src != dst) {
269             memcpy(dst, src, count * sizeof(SkPMColor));
270         }
271         return;
272     }
273
274 #ifdef SK_SUPPORT_LEGACY_INT_COLORMATRIX
275     const bool use_floats = false;
276 #else
277     const bool use_floats = true;
278 #endif
279
280     if (use_floats) {
281         // c0-c3 are already in [0,1].
282         const Sk4f c0 = Sk4f::Load(fTranspose + 0);
283         const Sk4f c1 = Sk4f::Load(fTranspose + 4);
284         const Sk4f c2 = Sk4f::Load(fTranspose + 8);
285         const Sk4f c3 = Sk4f::Load(fTranspose + 12);
286         // c4 (the translate vector) is in [0, 255].  Bring it back to [0,1].
287         const Sk4f c4 = Sk4f::Load(fTranspose + 16)*Sk4f(1.0f/255);
288
289         // todo: we could cache this in the constructor...
290         SkPMColor matrix_translate_pmcolor = round(premul(clamp_0_1(c4)));
291
292         for (int i = 0; i < count; i++) {
293             const SkPMColor src_c = src[i];
294             if (0 == src_c) {
295                 dst[i] = matrix_translate_pmcolor;
296                 continue;
297             }
298
299             Sk4f srcf = Sk4f::FromBytes((const uint8_t*)&src_c) * Sk4f(1.0f/255);
300
301             if (0xFF != SkGetPackedA32(src_c)) {
302                 srcf = unpremul(srcf);
303             }
304
305             Sk4f r4 = SkNx_dup<SK_R32_SHIFT/8>(srcf);
306             Sk4f g4 = SkNx_dup<SK_G32_SHIFT/8>(srcf);
307             Sk4f b4 = SkNx_dup<SK_B32_SHIFT/8>(srcf);
308             Sk4f a4 = SkNx_dup<SK_A32_SHIFT/8>(srcf);
309
310             // apply matrix
311             Sk4f dst4 = c0 * r4 + c1 * g4 + c2 * b4 + c3 * a4 + c4;
312
313             // clamp, re-premul, and write
314             dst[i] = round(premul(clamp_0_1(dst4)));
315         }
316     } else {
317         const State& state = fState;
318         int32_t result[4];
319         const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
320
321         for (int i = 0; i < count; i++) {
322             SkPMColor c = src[i];
323
324             unsigned r = SkGetPackedR32(c);
325             unsigned g = SkGetPackedG32(c);
326             unsigned b = SkGetPackedB32(c);
327             unsigned a = SkGetPackedA32(c);
328
329             // need our components to be un-premultiplied
330             if (255 != a) {
331                 SkUnPreMultiply::Scale scale = table[a];
332                 r = SkUnPreMultiply::ApplyScale(scale, r);
333                 g = SkUnPreMultiply::ApplyScale(scale, g);
334                 b = SkUnPreMultiply::ApplyScale(scale, b);
335
336                 SkASSERT(r <= 255);
337                 SkASSERT(g <= 255);
338                 SkASSERT(b <= 255);
339             }
340
341             proc(state, r, g, b, a, result);
342
343             r = pin(result[0], SK_R32_MASK);
344             g = pin(result[1], SK_G32_MASK);
345             b = pin(result[2], SK_B32_MASK);
346             a = pin(result[3], SK_A32_MASK);
347             // re-prepremultiply if needed
348             dst[i] = SkPremultiplyARGBInline(a, r, g, b);
349         }
350     }
351 }
352
353 ///////////////////////////////////////////////////////////////////////////////
354
355 void SkColorMatrixFilter::flatten(SkWriteBuffer& buffer) const {
356     SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20);
357     buffer.writeScalarArray(fMatrix.fMat, 20);
358 }
359
360 SkFlattenable* SkColorMatrixFilter::CreateProc(SkReadBuffer& buffer) {
361     SkColorMatrix matrix;
362     if (buffer.readScalarArray(matrix.fMat, 20)) {
363         return Create(matrix);
364     }
365     return nullptr;
366 }
367
368 bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const {
369     if (matrix) {
370         memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar));
371     }
372     return true;
373 }
374
375 SkColorFilter* SkColorMatrixFilter::newComposed(const SkColorFilter* innerFilter) const {
376     SkScalar innerMatrix[20];
377     if (innerFilter->asColorMatrix(innerMatrix) && !SkColorMatrix::NeedsClamping(innerMatrix)) {
378         SkScalar concat[20];
379         SkColorMatrix::SetConcat(concat, fMatrix.fMat, innerMatrix);
380         return SkColorMatrixFilter::Create(concat);
381     }
382     return nullptr;
383 }
384
385 #if SK_SUPPORT_GPU
386 #include "GrFragmentProcessor.h"
387 #include "GrInvariantOutput.h"
388 #include "glsl/GrGLSLFragmentProcessor.h"
389 #include "glsl/GrGLSLFragmentShaderBuilder.h"
390 #include "glsl/GrGLSLProgramDataManager.h"
391 #include "glsl/GrGLSLUniformHandler.h"
392
393 class ColorMatrixEffect : public GrFragmentProcessor {
394 public:
395     static const GrFragmentProcessor* Create(const SkColorMatrix& matrix) {
396         return new ColorMatrixEffect(matrix);
397     }
398
399     const char* name() const override { return "Color Matrix"; }
400
401     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
402
403     class GLSLProcessor : public GrGLSLFragmentProcessor {
404     public:
405         // this class always generates the same code.
406         static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {}
407
408         GLSLProcessor(const GrProcessor&) {}
409
410         virtual void emitCode(EmitArgs& args) override {
411             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
412             fMatrixHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
413                                                        kMat44f_GrSLType, kDefault_GrSLPrecision,
414                                                        "ColorMatrix");
415             fVectorHandle = uniformHandler->addUniform(GrGLSLUniformHandler::kFragment_Visibility,
416                                                        kVec4f_GrSLType, kDefault_GrSLPrecision,
417                                                        "ColorMatrixVector");
418
419             if (nullptr == args.fInputColor) {
420                 // could optimize this case, but we aren't for now.
421                 args.fInputColor = "vec4(1)";
422             }
423             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
424             // The max() is to guard against 0 / 0 during unpremul when the incoming color is
425             // transparent black.
426             fragBuilder->codeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n",
427                                      args.fInputColor);
428             fragBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
429                                      args.fOutputColor,
430                                      uniformHandler->getUniformCStr(fMatrixHandle),
431                                      args.fInputColor,
432                                      uniformHandler->getUniformCStr(fVectorHandle));
433             fragBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n",
434                                      args.fOutputColor, args.fOutputColor);
435             fragBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor);
436         }
437
438     protected:
439         virtual void onSetData(const GrGLSLProgramDataManager& uniManager,
440                                const GrProcessor& proc) override {
441             const ColorMatrixEffect& cme = proc.cast<ColorMatrixEffect>();
442             const float* m = cme.fMatrix.fMat;
443             // The GL matrix is transposed from SkColorMatrix.
444             float mt[]  = {
445                 m[0], m[5], m[10], m[15],
446                 m[1], m[6], m[11], m[16],
447                 m[2], m[7], m[12], m[17],
448                 m[3], m[8], m[13], m[18],
449             };
450             static const float kScale = 1.0f / 255.0f;
451             float vec[] = {
452                 m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale,
453             };
454             uniManager.setMatrix4fv(fMatrixHandle, 1, mt);
455             uniManager.set4fv(fVectorHandle, 1, vec);
456         }
457
458     private:
459         GrGLSLProgramDataManager::UniformHandle fMatrixHandle;
460         GrGLSLProgramDataManager::UniformHandle fVectorHandle;
461
462         typedef GrGLSLFragmentProcessor INHERITED;
463     };
464
465 private:
466     ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {
467         this->initClassID<ColorMatrixEffect>();
468     }
469
470     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
471         return new GLSLProcessor(*this);
472     }
473
474     virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
475                                        GrProcessorKeyBuilder* b) const override {
476         GLSLProcessor::GenKey(*this, caps, b);
477     }
478
479     bool onIsEqual(const GrFragmentProcessor& s) const override {
480         const ColorMatrixEffect& cme = s.cast<ColorMatrixEffect>();
481         return cme.fMatrix == fMatrix;
482     }
483
484     void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
485         // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had
486         // type flags it might be worth checking the other components.
487
488         // The matrix is defined such the 4th row determines the output alpha. The first four
489         // columns of that row multiply the input r, g, b, and a, respectively, and the last column
490         // is the "translation".
491         static const uint32_t kRGBAFlags[] = {
492             kR_GrColorComponentFlag,
493             kG_GrColorComponentFlag,
494             kB_GrColorComponentFlag,
495             kA_GrColorComponentFlag
496         };
497         static const int kShifts[] = {
498             GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
499         };
500         enum {
501             kAlphaRowStartIdx = 15,
502             kAlphaRowTranslateIdx = 19,
503         };
504
505         SkScalar outputA = 0;
506         for (int i = 0; i < 4; ++i) {
507             // If any relevant component of the color to be passed through the matrix is non-const
508             // then we can't know the final result.
509             if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
510                 if (!(inout->validFlags() & kRGBAFlags[i])) {
511                     inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
512                     return;
513                 } else {
514                     uint32_t component = (inout->color() >> kShifts[i]) & 0xFF;
515                     outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
516                 }
517             }
518         }
519         outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
520         // We pin the color to [0,1]. This would happen to the *final* color output from the frag
521         // shader but currently the effect does not pin its own output. So in the case of over/
522         // underflow this may deviate from the actual result. Maybe the effect should pin its
523         // result if the matrix could over/underflow for any component?
524         inout->setToOther(kA_GrColorComponentFlag,
525                           static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A,
526                           GrInvariantOutput::kWill_ReadInput);
527     }
528
529     SkColorMatrix fMatrix;
530
531     typedef GrFragmentProcessor INHERITED;
532 };
533
534 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect);
535
536 const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d) {
537     SkColorMatrix colorMatrix;
538     for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) {
539         colorMatrix.fMat[i] = d->fRandom->nextSScalar1();
540     }
541     return ColorMatrixEffect::Create(colorMatrix);
542 }
543
544 const GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*) const {
545     return ColorMatrixEffect::Create(fMatrix);
546 }
547
548 #endif
549
550 #ifndef SK_IGNORE_TO_STRING
551 void SkColorMatrixFilter::toString(SkString* str) const {
552     str->append("SkColorMatrixFilter: ");
553
554     str->append("matrix: (");
555     for (int i = 0; i < 20; ++i) {
556         str->appendScalar(fMatrix.fMat[i]);
557         if (i < 19) {
558             str->append(", ");
559         }
560     }
561     str->append(")");
562 }
563 #endif