1/*
2 * Copyright 2019 Google LLC
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
8in fragmentProcessor inputFP;
9layout(ctype=SkM44, tracked) in uniform half4x4 m;
10layout(ctype=SkV4, tracked) in uniform half4 v;
11layout(key) in bool unpremulInput;
12layout(key) in bool clampRGBOutput;
13layout(key) in bool premulOutput;
14
15@optimizationFlags {
16    ProcessorOptimizationFlags(inputFP.get()) & kConstantOutputForConstantInput_OptimizationFlag
17}
18
19half4 main() {
20    half4 color = sample(inputFP);
21    @if (unpremulInput) {
22        color = unpremul(color);
23    }
24    color = m * color + v;
25    @if (clampRGBOutput) {
26        color = saturate(color);
27    } else {
28        color.a = saturate(color.a);
29    }
30    @if (premulOutput) {
31        color.rgb *= color.a;
32    }
33    return color;
34}
35
36@class {
37    SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
38        SkPMColor4f input = ConstantOutputForConstantInput(this->childProcessor(0), inColor);
39        SkColor4f color;
40        if (unpremulInput) {
41            color = input.unpremul();
42        } else {
43            color.fR = input.fR;
44            color.fG = input.fG;
45            color.fB = input.fB;
46            color.fA = input.fA;
47        }
48        auto v4 = m.map(color.fR, color.fG, color.fB, color.fA) + v;
49        color = {v4.x, v4.y, v4.z, v4.w};
50        color.fA = SkTPin(color.fA, 0.f, 1.f);
51        if (clampRGBOutput) {
52            color.fR = SkTPin(color.fR, 0.f, 1.f);
53            color.fG = SkTPin(color.fG, 0.f, 1.f);
54            color.fB = SkTPin(color.fB, 0.f, 1.f);
55        }
56        if (premulOutput) {
57            return color.premul();
58        } else {
59            return {color.fR, color.fG, color.fB, color.fA};
60        }
61    }
62}
63
64@make {
65    static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP,
66                                                     const float matrix[20], bool unpremulInput,
67                                                     bool clampRGBOutput, bool premulOutput) {
68        SkM44 m44(
69            matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
70            matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
71            matrix[10], matrix[11], matrix[12], matrix[13],
72            matrix[15], matrix[16], matrix[17], matrix[18]
73        );
74        SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]};
75        return std::unique_ptr<GrFragmentProcessor>(new GrColorMatrixFragmentProcessor(
76            std::move(inputFP), m44, v4, unpremulInput, clampRGBOutput, premulOutput));
77    }
78}
79
80@test(d) {
81    float m[20];
82    for (int i = 0; i < 20; ++i) {
83        m[i] = d->fRandom->nextRangeScalar(-10.f, 10.f);
84    }
85    bool unpremul = d->fRandom->nextBool();
86    bool clampRGB = d->fRandom->nextBool();
87    bool premul = d->fRandom->nextBool();
88    return Make(d->inputFP(), m, unpremul, clampRGB, premul);
89}
90