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 "src/gpu/GrColorSpaceXform.h"
9 
10 #include "include/core/SkColorSpace.h"
11 #include "src/core/SkColorSpacePriv.h"
12 #include "src/gpu/GrColorInfo.h"
13 #include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
14 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
15 
Make(SkColorSpace* src, SkAlphaType srcAT, SkColorSpace* dst, SkAlphaType dstAT)16 sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkAlphaType srcAT,
17                                                  SkColorSpace* dst, SkAlphaType dstAT) {
18     SkColorSpaceXformSteps steps(src, srcAT, dst, dstAT);
19     return steps.flags.mask() == 0 ? nullptr  /* Noop transform */
20                                    : sk_make_sp<GrColorSpaceXform>(steps);
21 }
22 
Make(const GrColorInfo& srcInfo, const GrColorInfo& dstInfo)23 sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(const GrColorInfo& srcInfo,
24                                                  const GrColorInfo& dstInfo) {
25     return Make(srcInfo.colorSpace(), srcInfo.alphaType(),
26                 dstInfo.colorSpace(), dstInfo.alphaType());
27 }
28 
Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b)29 bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) {
30     if (a == b) {
31         return true;
32     }
33 
34     if (!a || !b || a->fSteps.flags.mask() != b->fSteps.flags.mask()) {
35         return false;
36     }
37 
38     if (a->fSteps.flags.linearize &&
39         0 != memcmp(&a->fSteps.srcTF, &b->fSteps.srcTF, sizeof(a->fSteps.srcTF))) {
40         return false;
41     }
42 
43     if (a->fSteps.flags.gamut_transform &&
44         0 != memcmp(&a->fSteps.src_to_dst_matrix, &b->fSteps.src_to_dst_matrix,
45                     sizeof(a->fSteps.src_to_dst_matrix))) {
46         return false;
47     }
48 
49     if (a->fSteps.flags.encode &&
50         0 != memcmp(&a->fSteps.dstTFInv, &b->fSteps.dstTFInv, sizeof(a->fSteps.dstTFInv))) {
51         return false;
52     }
53 
54     return true;
55 }
56 
apply(const SkColor4f& srcColor)57 SkColor4f GrColorSpaceXform::apply(const SkColor4f& srcColor) {
58     SkColor4f result = srcColor;
59     fSteps.apply(result.vec());
60     return result;
61 }
62 
63 //////////////////////////////////////////////////////////////////////////////
64 
GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child, sk_sp<GrColorSpaceXform> colorXform)65 GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
66                                                  sk_sp<GrColorSpaceXform> colorXform)
67         : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
68         , fColorXform(std::move(colorXform)) {
69     this->registerChild(std::move(child));
70 }
71 
GrColorSpaceXformEffect(const GrColorSpaceXformEffect& that)72 GrColorSpaceXformEffect::GrColorSpaceXformEffect(const GrColorSpaceXformEffect& that)
73         : INHERITED(that)
74         , fColorXform(that.fColorXform) {}
75 
clone() const76 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
77     return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(*this));
78 }
79 
onIsEqual(const GrFragmentProcessor& s) const80 bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
81     const GrColorSpaceXformEffect& other = s.cast<GrColorSpaceXformEffect>();
82     return GrColorSpaceXform::Equals(fColorXform.get(), other.fColorXform.get());
83 }
84 
getShaderDfxInfo() const85 SkString GrColorSpaceXformEffect::getShaderDfxInfo() const
86 {
87     SkString format;
88     format.printf("ShaderDfx_GrColorSpaceXformEffect_%d", GrColorSpaceXform::XformKey(fColorXform.get()));
89     return format;
90 }
91 
onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const92 void GrColorSpaceXformEffect::onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
93     b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
94 }
95 
96 std::unique_ptr<GrFragmentProcessor::ProgramImpl>
onMakeProgramImpl() const97 GrColorSpaceXformEffect::onMakeProgramImpl() const {
98     class Impl : public ProgramImpl {
99     public:
100         void emitCode(EmitArgs& args) override {
101             const GrColorSpaceXformEffect& proc = args.fFp.cast<GrColorSpaceXformEffect>();
102             GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
103             GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
104 
105             fColorSpaceHelper.emitCode(uniformHandler, proc.colorXform());
106 
107             SkString childColor = this->invokeChild(0, args);
108 
109             SkString xformedColor;
110             fragBuilder->appendColorGamutXform(
111                     &xformedColor, childColor.c_str(), &fColorSpaceHelper);
112             fragBuilder->codeAppendf("return %s;", xformedColor.c_str());
113         }
114 
115     private:
116         void onSetData(const GrGLSLProgramDataManager& pdman,
117                        const GrFragmentProcessor& fp) override {
118             const GrColorSpaceXformEffect& proc = fp.cast<GrColorSpaceXformEffect>();
119             fColorSpaceHelper.setData(pdman, proc.colorXform());
120         }
121 
122         GrGLSLColorSpaceXformHelper fColorSpaceHelper;
123     };
124 
125     return std::make_unique<Impl>();
126 }
127 
OptFlags( const GrFragmentProcessor* child)128 GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
129         const GrFragmentProcessor* child) {
130     return ProcessorOptimizationFlags(child) & (kCompatibleWithCoverageAsAlpha_OptimizationFlag |
131                                                 kPreservesOpaqueInput_OptimizationFlag |
132                                                 kConstantOutputForConstantInput_OptimizationFlag);
133 }
134 
constantOutputForConstantInput( const SkPMColor4f& input) const135 SkPMColor4f GrColorSpaceXformEffect::constantOutputForConstantInput(
136         const SkPMColor4f& input) const {
137     const auto c0 = ConstantOutputForConstantInput(this->childProcessor(0), input);
138     return this->fColorXform->apply(c0.unpremul()).premul();
139 }
140 
Make( std::unique_ptr<GrFragmentProcessor> child, SkColorSpace* src, SkAlphaType srcAT, SkColorSpace* dst, SkAlphaType dstAT)141 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
142         std::unique_ptr<GrFragmentProcessor> child,
143         SkColorSpace* src, SkAlphaType srcAT,
144         SkColorSpace* dst, SkAlphaType dstAT) {
145     return Make(std::move(child), GrColorSpaceXform::Make(src, srcAT, dst, dstAT));
146 }
147 
Make( std::unique_ptr<GrFragmentProcessor> child, const GrColorInfo& srcInfo, const GrColorInfo& dstInfo)148 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
149         std::unique_ptr<GrFragmentProcessor> child,
150         const GrColorInfo& srcInfo,
151         const GrColorInfo& dstInfo) {
152     return Make(std::move(child), GrColorSpaceXform::Make(srcInfo, dstInfo));
153 }
154 
Make( std::unique_ptr<GrFragmentProcessor> child, sk_sp<GrColorSpaceXform> colorXform)155 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
156         std::unique_ptr<GrFragmentProcessor> child,
157         sk_sp<GrColorSpaceXform> colorXform) {
158     if (!colorXform) {
159         return child;
160     }
161 
162     return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
163                                                                             std::move(colorXform)));
164 }
165