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/ganesh/GrColorSpaceXform.h"
9
10 #include "include/core/SkString.h"
11 #include "modules/skcms/skcms.h"
12 #include "src/gpu/KeyBuilder.h"
13 #include "src/gpu/ganesh/GrColorInfo.h"
14 #include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
15 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
16
17 #include <cstring>
18 #include <utility>
19
20 class GrGLSLProgramDataManager;
21 class GrGLSLUniformHandler;
22 enum SkAlphaType : int;
23 struct GrShaderCaps;
24
Make(SkColorSpace * src,SkAlphaType srcAT,SkColorSpace * dst,SkAlphaType dstAT)25 sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkAlphaType srcAT,
26 SkColorSpace* dst, SkAlphaType dstAT) {
27 SkColorSpaceXformSteps steps(src, srcAT, dst, dstAT);
28 return steps.flags.mask() == 0 ? nullptr /* Noop transform */
29 : sk_make_sp<GrColorSpaceXform>(steps);
30 }
31
Make(const GrColorInfo & srcInfo,const GrColorInfo & dstInfo)32 sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(const GrColorInfo& srcInfo,
33 const GrColorInfo& dstInfo) {
34 return Make(srcInfo.colorSpace(), srcInfo.alphaType(),
35 dstInfo.colorSpace(), dstInfo.alphaType());
36 }
37
XformKey(const GrColorSpaceXform * xform)38 uint32_t GrColorSpaceXform::XformKey(const GrColorSpaceXform* xform) {
39 // Code generation depends on which steps we apply,
40 // and the kinds of transfer functions (if we're applying those).
41 if (!xform) { return 0; }
42
43 const SkColorSpaceXformSteps& steps(xform->fSteps);
44 uint32_t key = steps.flags.mask();
45 if (steps.flags.linearize) {
46 key |= skcms_TransferFunction_getType(&steps.srcTF) << 8;
47 }
48 if (steps.flags.encode) {
49 key |= skcms_TransferFunction_getType(&steps.dstTFInv) << 16;
50 }
51 return key;
52 }
53
Equals(const GrColorSpaceXform * a,const GrColorSpaceXform * b)54 bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) {
55 if (a == b) {
56 return true;
57 }
58
59 if (!a || !b || a->fSteps.flags.mask() != b->fSteps.flags.mask()) {
60 return false;
61 }
62
63 if (a->fSteps.flags.linearize &&
64 0 != memcmp(&a->fSteps.srcTF, &b->fSteps.srcTF, sizeof(a->fSteps.srcTF))) {
65 return false;
66 }
67
68 if (a->fSteps.flags.gamut_transform &&
69 0 != memcmp(&a->fSteps.src_to_dst_matrix, &b->fSteps.src_to_dst_matrix,
70 sizeof(a->fSteps.src_to_dst_matrix))) {
71 return false;
72 }
73
74 if (a->fSteps.flags.encode &&
75 0 != memcmp(&a->fSteps.dstTFInv, &b->fSteps.dstTFInv, sizeof(a->fSteps.dstTFInv))) {
76 return false;
77 }
78
79 return true;
80 }
81
apply(const SkColor4f & srcColor)82 SkColor4f GrColorSpaceXform::apply(const SkColor4f& srcColor) {
83 SkColor4f result = srcColor;
84 fSteps.apply(result.vec());
85 return result;
86 }
87
88 //////////////////////////////////////////////////////////////////////////////
89
GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,sk_sp<GrColorSpaceXform> colorXform)90 GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
91 sk_sp<GrColorSpaceXform> colorXform)
92 : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
93 , fColorXform(std::move(colorXform)) {
94 this->registerChild(std::move(child));
95 }
96
GrColorSpaceXformEffect(const GrColorSpaceXformEffect & that)97 GrColorSpaceXformEffect::GrColorSpaceXformEffect(const GrColorSpaceXformEffect& that)
98 : INHERITED(that)
99 , fColorXform(that.fColorXform) {}
100
clone() const101 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
102 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(*this));
103 }
104
onIsEqual(const GrFragmentProcessor & s) const105 bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
106 const GrColorSpaceXformEffect& other = s.cast<GrColorSpaceXformEffect>();
107 return GrColorSpaceXform::Equals(fColorXform.get(), other.fColorXform.get());
108 }
109
onAddToKey(const GrShaderCaps &,skgpu::KeyBuilder * b) const110 void GrColorSpaceXformEffect::onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const {
111 b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
112 }
113
114 std::unique_ptr<GrFragmentProcessor::ProgramImpl>
onMakeProgramImpl() const115 GrColorSpaceXformEffect::onMakeProgramImpl() const {
116 class Impl : public ProgramImpl {
117 public:
118 void emitCode(EmitArgs& args) override {
119 const GrColorSpaceXformEffect& proc = args.fFp.cast<GrColorSpaceXformEffect>();
120 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
121 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
122
123 fColorSpaceHelper.emitCode(uniformHandler, proc.colorXform());
124
125 SkString childColor = this->invokeChild(0, args);
126
127 SkString xformedColor;
128 fragBuilder->appendColorGamutXform(
129 &xformedColor, childColor.c_str(), &fColorSpaceHelper);
130 fragBuilder->codeAppendf("return %s;", xformedColor.c_str());
131 }
132
133 private:
134 void onSetData(const GrGLSLProgramDataManager& pdman,
135 const GrFragmentProcessor& fp) override {
136 const GrColorSpaceXformEffect& proc = fp.cast<GrColorSpaceXformEffect>();
137 fColorSpaceHelper.setData(pdman, proc.colorXform());
138 }
139
140 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
141 };
142
143 return std::make_unique<Impl>();
144 }
145
OptFlags(const GrFragmentProcessor * child)146 GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
147 const GrFragmentProcessor* child) {
148 return ProcessorOptimizationFlags(child) & (kCompatibleWithCoverageAsAlpha_OptimizationFlag |
149 kPreservesOpaqueInput_OptimizationFlag |
150 kConstantOutputForConstantInput_OptimizationFlag);
151 }
152
constantOutputForConstantInput(const SkPMColor4f & input) const153 SkPMColor4f GrColorSpaceXformEffect::constantOutputForConstantInput(
154 const SkPMColor4f& input) const {
155 const auto c0 = ConstantOutputForConstantInput(this->childProcessor(0), input);
156 return this->fColorXform->apply(c0.unpremul()).premul();
157 }
158
Make(std::unique_ptr<GrFragmentProcessor> child,SkColorSpace * src,SkAlphaType srcAT,SkColorSpace * dst,SkAlphaType dstAT)159 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
160 std::unique_ptr<GrFragmentProcessor> child,
161 SkColorSpace* src, SkAlphaType srcAT,
162 SkColorSpace* dst, SkAlphaType dstAT) {
163 return Make(std::move(child), GrColorSpaceXform::Make(src, srcAT, dst, dstAT));
164 }
165
Make(std::unique_ptr<GrFragmentProcessor> child,const GrColorInfo & srcInfo,const GrColorInfo & dstInfo)166 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
167 std::unique_ptr<GrFragmentProcessor> child,
168 const GrColorInfo& srcInfo,
169 const GrColorInfo& dstInfo) {
170 return Make(std::move(child), GrColorSpaceXform::Make(srcInfo, dstInfo));
171 }
172
Make(std::unique_ptr<GrFragmentProcessor> child,sk_sp<GrColorSpaceXform> colorXform)173 std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
174 std::unique_ptr<GrFragmentProcessor> child,
175 sk_sp<GrColorSpaceXform> colorXform) {
176 if (!colorXform) {
177 return child;
178 }
179
180 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
181 std::move(colorXform)));
182 }
183