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