1 /*
2  * Copyright 2016 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 "GrColorSpaceXform.h"
9 #include "SkColorSpace.h"
10 #include "SkColorSpacePriv.h"
11 #include "glsl/GrGLSLColorSpaceXformHelper.h"
12 #include "glsl/GrGLSLFragmentProcessor.h"
13 #include "glsl/GrGLSLFragmentShaderBuilder.h"
14 
15 sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkAlphaType srcAT,
16                                                  SkColorSpace* dst, SkAlphaType dstAT) {
17     SkColorSpaceXformSteps steps(src, srcAT, dst, dstAT);
18     return steps.flags.mask() == 0 ? nullptr  /* Noop transform */
19                                    : sk_make_sp<GrColorSpaceXform>(steps);
20 }
21 
22 bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) {
23     if (a == b) {
24         return true;
25     }
26 
27     if (!a || !b || a->fSteps.flags.mask() != b->fSteps.flags.mask()) {
28         return false;
29     }
30 
31     if (a->fSteps.flags.linearize &&
32         0 != memcmp(&a->fSteps.srcTF, &b->fSteps.srcTF, sizeof(a->fSteps.srcTF))) {
33         return false;
34     }
35 
36     if (a->fSteps.flags.gamut_transform &&
37         0 != memcmp(&a->fSteps.src_to_dst_matrix, &b->fSteps.src_to_dst_matrix,
38                     sizeof(a->fSteps.src_to_dst_matrix))) {
39         return false;
40     }
41 
42     if (a->fSteps.flags.encode &&
43         0 != memcmp(&a->fSteps.dstTFInv, &b->fSteps.dstTFInv, sizeof(a->fSteps.dstTFInv))) {
44         return false;
45     }
46 
47     return true;
48 }
49 
50 SkColor4f GrColorSpaceXform::apply(const SkColor4f& srcColor) {
51     SkColor4f result = srcColor;
52     fSteps.apply(result.vec());
53     return result;
54 }
55 
56 //////////////////////////////////////////////////////////////////////////////
57 
58 class GrGLColorSpaceXformEffect : public GrGLSLFragmentProcessor {
59 public:
60     void emitCode(EmitArgs& args) override {
61         const GrColorSpaceXformEffect& csxe = args.fFp.cast<GrColorSpaceXformEffect>();
62         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
63         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
64 
65         fColorSpaceHelper.emitCode(uniformHandler, csxe.colorXform());
66 
67         if (this->numChildProcessors()) {
68             SkString childColor("src_color");
69             this->emitChild(0, &childColor, args);
70 
71             SkString xformedColor;
72             fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper);
73             fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(),
74                                      args.fInputColor);
75         } else {
76             SkString xformedColor;
77             fragBuilder->appendColorGamutXform(&xformedColor, args.fInputColor, &fColorSpaceHelper);
78             fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str());
79         }
80     }
81 
82 private:
83     void onSetData(const GrGLSLProgramDataManager& pdman,
84                    const GrFragmentProcessor& processor) override {
85         const GrColorSpaceXformEffect& csxe = processor.cast<GrColorSpaceXformEffect>();
86         fColorSpaceHelper.setData(pdman, csxe.colorXform());
87     }
88 
89     GrGLSLColorSpaceXformHelper fColorSpaceHelper;
90 
91     typedef GrGLSLFragmentProcessor INHERITED;
92 };
93 
94 //////////////////////////////////////////////////////////////////////////////
95 
96 GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
97                                                  sk_sp<GrColorSpaceXform> colorXform)
98         : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
99         , fColorXform(std::move(colorXform)) {
100     if (child) {
101         this->registerChildProcessor(std::move(child));
102     }
103 }
104 
105 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
106     std::unique_ptr<GrFragmentProcessor> child =
107             this->numChildProcessors() ? this->childProcessor(0).clone() : nullptr;
108     return std::unique_ptr<GrFragmentProcessor>(
109             new GrColorSpaceXformEffect(std::move(child), fColorXform));
110 }
111 
112 bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
113     const GrColorSpaceXformEffect& other = s.cast<GrColorSpaceXformEffect>();
114     return GrColorSpaceXform::Equals(fColorXform.get(), other.fColorXform.get());
115 }
116 
117 void GrColorSpaceXformEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
118                                                     GrProcessorKeyBuilder* b) const {
119     b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
120 }
121 
122 GrGLSLFragmentProcessor* GrColorSpaceXformEffect::onCreateGLSLInstance() const {
123     return new GrGLColorSpaceXformEffect();
124 }
125 
126 GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
127         const GrFragmentProcessor* child) {
128     // TODO: Implement constant output for constant input
129     if (child) {
130         OptimizationFlags flags = kNone_OptimizationFlags;
131         if (child->compatibleWithCoverageAsAlpha()) {
132             flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
133         }
134         if (child->preservesOpaqueInput()) {
135             flags |= kPreservesOpaqueInput_OptimizationFlag;
136         }
137         return flags;
138     } else {
139         return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
140                kPreservesOpaqueInput_OptimizationFlag;
141     }
142 }
143 
144 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(SkColorSpace* src,
145                                                                    SkAlphaType srcAT,
146                                                                    SkColorSpace* dst,
147                                                                    SkAlphaType dstAT) {
148     auto xform = GrColorSpaceXform::Make(src, srcAT,
149                                          dst, dstAT);
150     if (!xform) {
151         return nullptr;
152     }
153 
154     return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(nullptr,
155                                                                             std::move(xform)));
156 }
157 
158 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
159         std::unique_ptr<GrFragmentProcessor> child,
160         SkColorSpace* src, SkAlphaType srcAT, SkColorSpace* dst) {
161     if (!child) {
162         return nullptr;
163     }
164 
165     auto xform = GrColorSpaceXform::Make(src, srcAT,
166                                          dst, kPremul_SkAlphaType);
167     if (!xform) {
168         return child;
169     }
170 
171     return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
172                                                                             std::move(xform)));
173 }
174 
175 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
176         std::unique_ptr<GrFragmentProcessor> child, sk_sp<GrColorSpaceXform> colorXform) {
177     if (!child) {
178         return nullptr;
179     }
180     if (!colorXform) {
181         return child;
182     }
183 
184     return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
185                                                                             std::move(colorXform)));
186 }
187