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 "include/core/SkColorSpace.h"
9#include "src/core/SkColorSpacePriv.h"
10#include "src/gpu/GrColorSpaceXform.h"
11#include "src/gpu/glsl/GrGLSLColorSpaceXformHelper.h"
12#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
13#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14
15sk_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
22bool 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
50SkColor4f GrColorSpaceXform::apply(const SkColor4f& srcColor) {
51 SkColor4f result = srcColor;
52 fSteps.apply(result.vec());
53 return result;
54}
55
56//////////////////////////////////////////////////////////////////////////////
57
58class GrGLColorSpaceXformEffect : public GrGLSLFragmentProcessor {
59public:
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 = this->invokeChild(0, args);
69
70 SkString xformedColor;
71 fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper);
72 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(),
73 args.fInputColor);
74 } else {
75 SkString xformedColor;
76 fragBuilder->appendColorGamutXform(&xformedColor, args.fInputColor, &fColorSpaceHelper);
77 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str());
78 }
79 }
80
81private:
82 void onSetData(const GrGLSLProgramDataManager& pdman,
83 const GrFragmentProcessor& processor) override {
84 const GrColorSpaceXformEffect& csxe = processor.cast<GrColorSpaceXformEffect>();
85 fColorSpaceHelper.setData(pdman, csxe.colorXform());
86 }
87
88 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
89
90 typedef GrGLSLFragmentProcessor INHERITED;
91};
92
93//////////////////////////////////////////////////////////////////////////////
94
95GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
96 sk_sp<GrColorSpaceXform> colorXform)
97 : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
98 , fColorXform(std::move(colorXform)) {
99 if (child) {
100 this->registerChildProcessor(std::move(child));
101 }
102}
103
104std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
105 std::unique_ptr<GrFragmentProcessor> child =
106 this->numChildProcessors() ? this->childProcessor(0).clone() : nullptr;
107 return std::unique_ptr<GrFragmentProcessor>(
108 new GrColorSpaceXformEffect(std::move(child), fColorXform));
109}
110
111bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
112 const GrColorSpaceXformEffect& other = s.cast<GrColorSpaceXformEffect>();
113 return GrColorSpaceXform::Equals(fColorXform.get(), other.fColorXform.get());
114}
115
116void GrColorSpaceXformEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
117 GrProcessorKeyBuilder* b) const {
118 b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
119}
120
121GrGLSLFragmentProcessor* GrColorSpaceXformEffect::onCreateGLSLInstance() const {
122 return new GrGLColorSpaceXformEffect();
123}
124
125GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
126 const GrFragmentProcessor* child) {
127 if (child) {
128 OptimizationFlags flags = kNone_OptimizationFlags;
129 if (child->compatibleWithCoverageAsAlpha()) {
130 flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
131 }
132 if (child->preservesOpaqueInput()) {
133 flags |= kPreservesOpaqueInput_OptimizationFlag;
134 }
135 if (child->hasConstantOutputForConstantInput()) {
136 flags |= kConstantOutputForConstantInput_OptimizationFlag;
137 }
138 return flags;
139 } else {
140 return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
141 kPreservesOpaqueInput_OptimizationFlag |
142 kConstantOutputForConstantInput_OptimizationFlag;
143 }
144}
145
146SkPMColor4f GrColorSpaceXformEffect::constantOutputForConstantInput(
147 const SkPMColor4f& input) const {
148 const auto c0 = this->numChildProcessors()
149 ? ConstantOutputForConstantInput(this->childProcessor(0), input)
150 : input;
151 return this->fColorXform->apply(c0.unpremul()).premul();
152}
153
154std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(SkColorSpace* src,
155 SkAlphaType srcAT,
156 SkColorSpace* dst,
157 SkAlphaType dstAT) {
158 auto xform = GrColorSpaceXform::Make(src, srcAT,
159 dst, dstAT);
160 if (!xform) {
161 return nullptr;
162 }
163
164 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(nullptr,
165 std::move(xform)));
166}
167
168std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
169 std::unique_ptr<GrFragmentProcessor> child,
170 SkColorSpace* src, SkAlphaType srcAT, SkColorSpace* dst) {
171 if (!child) {
172 return nullptr;
173 }
174
175 auto xform = GrColorSpaceXform::Make(src, srcAT,
176 dst, kPremul_SkAlphaType);
177 if (!xform) {
178 return child;
179 }
180
181 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
182 std::move(xform)));
183}
184
185std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
186 std::unique_ptr<GrFragmentProcessor> child, sk_sp<GrColorSpaceXform> colorXform) {
187 if (!child) {
188 return nullptr;
189 }
190 if (!colorXform) {
191 return child;
192 }
193
194 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
195 std::move(colorXform)));
196}
197