blob: 4ccca5218564d607949344222a9479f7908b3d9f [file] [log] [blame]
brianosman54f30c12016-07-18 10:53:52 -07001/*
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"
Brian Osmanf06ead92017-10-30 13:47:41 -040010#include "SkColorSpacePriv.h"
brianosman9f978822016-07-27 05:25:26 -070011#include "SkMatrix44.h"
Brian Osmanc4f93ca2017-10-17 17:15:52 -040012#include "glsl/GrGLSLColorSpaceXformHelper.h"
13#include "glsl/GrGLSLFragmentProcessor.h"
14#include "glsl/GrGLSLFragmentShaderBuilder.h"
Brian Osman7c2114f2016-10-20 15:34:06 -040015
Brian Osman653f34d2018-06-14 11:44:02 -040016sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkColorSpace* dst) {
Brian Osman3567c142018-06-18 10:20:32 -040017 // No transformation is performed in legacy mode, until SkColorSpaceXformCanvas is gone
Brian Osmanf06ead92017-10-30 13:47:41 -040018 if (!dst) {
brianosman54f30c12016-07-18 10:53:52 -070019 return nullptr;
20 }
21
Brian Osman3567c142018-06-18 10:20:32 -040022 // Treat null sources as sRGB (safe because sRGB is a global singleton)
Brian Osmanf06ead92017-10-30 13:47:41 -040023 if (!src) {
Brian Osman653f34d2018-06-14 11:44:02 -040024 src = SkColorSpace::MakeSRGB().get();
Brian Osmanf06ead92017-10-30 13:47:41 -040025 }
26
Brian Osman3567c142018-06-18 10:20:32 -040027 // TODO: Plumb source alpha type
28 SkColorSpaceXformSteps steps(src, kPremul_SkAlphaType, dst);
Brian Osmanf06ead92017-10-30 13:47:41 -040029
Brian Osman3567c142018-06-18 10:20:32 -040030 return steps.flags.mask() == 0 ? nullptr /* Noop transform */
31 : sk_make_sp<GrColorSpaceXform>(steps);
32}
33
34sk_sp<GrColorSpaceXform> GrColorSpaceXform::MakeUnpremulToUnpremul(SkColorSpace* src,
35 SkColorSpace* dst) {
36 // No transformation is performed in legacy mode, until SkColorSpaceXformCanvas is gone
37 if (!dst) {
Brian Osman653f34d2018-06-14 11:44:02 -040038 return nullptr;
Brian Osmanf06ead92017-10-30 13:47:41 -040039 }
Brian Osman653f34d2018-06-14 11:44:02 -040040
Brian Osman3567c142018-06-18 10:20:32 -040041 // Treat null sources as sRGB (safe because sRGB is a global singleton)
42 if (!src) {
43 src = SkColorSpace::MakeSRGB().get();
brianosman54f30c12016-07-18 10:53:52 -070044 }
Brian Osman7c2114f2016-10-20 15:34:06 -040045
Brian Osman3567c142018-06-18 10:20:32 -040046 SkColorSpaceXformSteps steps = SkColorSpaceXformSteps::UnpremulToUnpremul(src, dst);
brianosman54f30c12016-07-18 10:53:52 -070047
Brian Osman3567c142018-06-18 10:20:32 -040048 return steps.flags.mask() == 0 ? nullptr /* Noop transform */
49 : sk_make_sp<GrColorSpaceXform>(steps);
brianosman54f30c12016-07-18 10:53:52 -070050}
brianosman5a7ae7e2016-09-12 12:07:25 -070051
brianosmanb9c51372016-09-15 11:09:45 -070052bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) {
53 if (a == b) {
54 return true;
55 }
56
Brian Osman3567c142018-06-18 10:20:32 -040057 if (!a || !b || a->fSteps.flags.mask() != b->fSteps.flags.mask()) {
brianosmanb9c51372016-09-15 11:09:45 -070058 return false;
59 }
60
Brian Osman3567c142018-06-18 10:20:32 -040061 if (a->fSteps.flags.linearize &&
62 0 != memcmp(&a->fSteps.srcTF, &b->fSteps.srcTF, sizeof(a->fSteps.srcTF))) {
Brian Osmanf06ead92017-10-30 13:47:41 -040063 return false;
64 }
65
Brian Osman3567c142018-06-18 10:20:32 -040066 if (a->fSteps.flags.gamut_transform &&
67 0 != memcmp(&a->fSteps.src_to_dst_matrix, &b->fSteps.src_to_dst_matrix,
68 sizeof(a->fSteps.src_to_dst_matrix))) {
69 return false;
70 }
71
72 if (a->fSteps.flags.encode &&
73 0 != memcmp(&a->fSteps.dstTFInv, &b->fSteps.dstTFInv, sizeof(a->fSteps.dstTFInv))) {
Brian Osmanf06ead92017-10-30 13:47:41 -040074 return false;
75 }
76
77 return true;
brianosmanb9c51372016-09-15 11:09:45 -070078}
79
Brian Osman3567c142018-06-18 10:20:32 -040080GrColor4f GrColorSpaceXform::apply(const GrColor4f& srcColor) {
Brian Osmanf06ead92017-10-30 13:47:41 -040081 GrColor4f result = srcColor;
Brian Osman3567c142018-06-18 10:20:32 -040082 fSteps.apply(result.fRGBA);
brianosman5a7ae7e2016-09-12 12:07:25 -070083 return result;
84}
Brian Osmanc4f93ca2017-10-17 17:15:52 -040085
86//////////////////////////////////////////////////////////////////////////////
87
88class GrGLColorSpaceXformEffect : public GrGLSLFragmentProcessor {
89public:
90 void emitCode(EmitArgs& args) override {
91 const GrColorSpaceXformEffect& csxe = args.fFp.cast<GrColorSpaceXformEffect>();
92 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
93 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
94
95 fColorSpaceHelper.emitCode(uniformHandler, csxe.colorXform());
96
Brian Osman3567c142018-06-18 10:20:32 -040097 if (this->numChildProcessors()) {
98 SkString childColor("src_color");
99 this->emitChild(0, &childColor, args);
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400100
Brian Osman3567c142018-06-18 10:20:32 -0400101 SkString xformedColor;
102 fragBuilder->appendColorGamutXform(&xformedColor, childColor.c_str(), &fColorSpaceHelper);
103 fragBuilder->codeAppendf("%s = %s * %s;", args.fOutputColor, xformedColor.c_str(),
104 args.fInputColor);
105 } else {
106 if (nullptr == args.fInputColor) {
107 args.fInputColor = "half4(1)";
108 }
109 SkString xformedColor;
110 fragBuilder->appendColorGamutXform(&xformedColor, args.fInputColor, &fColorSpaceHelper);
111 fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, xformedColor.c_str());
112 }
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400113 }
114
115private:
116 void onSetData(const GrGLSLProgramDataManager& pdman,
117 const GrFragmentProcessor& processor) override {
118 const GrColorSpaceXformEffect& csxe = processor.cast<GrColorSpaceXformEffect>();
Brian Osmanc891b102018-06-14 14:50:17 -0400119 fColorSpaceHelper.setData(pdman, csxe.colorXform());
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400120 }
121
122 GrGLSLColorSpaceXformHelper fColorSpaceHelper;
123
124 typedef GrGLSLFragmentProcessor INHERITED;
125};
126
127//////////////////////////////////////////////////////////////////////////////
128
129GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
130 sk_sp<GrColorSpaceXform> colorXform)
131 : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
132 , fColorXform(std::move(colorXform)) {
Brian Osman3567c142018-06-18 10:20:32 -0400133 if (child) {
134 this->registerChildProcessor(std::move(child));
135 }
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400136}
137
138std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
Brian Osman3567c142018-06-18 10:20:32 -0400139 std::unique_ptr<GrFragmentProcessor> child =
140 this->numChildProcessors() ? this->childProcessor(0).clone() : nullptr;
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400141 return std::unique_ptr<GrFragmentProcessor>(
Brian Osman3567c142018-06-18 10:20:32 -0400142 new GrColorSpaceXformEffect(std::move(child), fColorXform));
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400143}
144
145bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
146 const GrColorSpaceXformEffect& other = s.cast<GrColorSpaceXformEffect>();
147 return GrColorSpaceXform::Equals(fColorXform.get(), other.fColorXform.get());
148}
149
150void GrColorSpaceXformEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
151 GrProcessorKeyBuilder* b) const {
152 b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
153}
154
155GrGLSLFragmentProcessor* GrColorSpaceXformEffect::onCreateGLSLInstance() const {
156 return new GrGLColorSpaceXformEffect();
157}
158
159GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
160 const GrFragmentProcessor* child) {
161 // TODO: Implement constant output for constant input
Brian Osman3567c142018-06-18 10:20:32 -0400162 if (child) {
163 OptimizationFlags flags = kNone_OptimizationFlags;
164 if (child->compatibleWithCoverageAsAlpha()) {
165 flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag;
166 }
167 if (child->preservesOpaqueInput()) {
168 flags |= kPreservesOpaqueInput_OptimizationFlag;
169 }
170 return flags;
171 } else {
172 return kCompatibleWithCoverageAsAlpha_OptimizationFlag |
173 kPreservesOpaqueInput_OptimizationFlag;
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400174 }
Brian Osman3567c142018-06-18 10:20:32 -0400175}
176
177std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(SkColorSpace* src,
178 SkColorSpace* dst) {
179 auto xform = GrColorSpaceXform::Make(src, dst);
180 if (!xform) {
181 return nullptr;
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400182 }
Brian Osman3567c142018-06-18 10:20:32 -0400183
184 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(nullptr,
185 std::move(xform)));
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400186}
187
188std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
189 std::unique_ptr<GrFragmentProcessor> child,
Brian Osman653f34d2018-06-14 11:44:02 -0400190 SkColorSpace* src, SkColorSpace* dst) {
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400191 if (!child) {
192 return nullptr;
193 }
194
Brian Osman3567c142018-06-18 10:20:32 -0400195 auto xform = GrColorSpaceXform::Make(src, dst);
196 if (!xform) {
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400197 return child;
198 }
Brian Osman3567c142018-06-18 10:20:32 -0400199
200 return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
201 std::move(xform)));
Brian Osmanc4f93ca2017-10-17 17:15:52 -0400202}