blob: 120304bac4226206e33fcb547c35dd8167f941bd [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/ganesh/GrColorSpaceXform.h"
#include "include/core/SkString.h"
#include "modules/skcms/skcms.h"
#include "src/core/SkColorSpacePriv.h"
#include "src/gpu/KeyBuilder.h"
#include "src/gpu/ganesh/GrColorInfo.h"
#include "src/gpu/ganesh/GrProcessor.h"
#include "src/gpu/ganesh/glsl/GrGLSLColorSpaceXformHelper.h"
#include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
#include <string.h>
#include <utility>
class GrGLSLProgramDataManager;
class GrGLSLUniformHandler;
struct GrShaderCaps;
sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst, SkAlphaType dstAT) {
SkColorSpaceXformSteps steps(src, srcAT, dst, dstAT);
return steps.flags.mask() == 0 ? nullptr /* Noop transform */
: sk_make_sp<GrColorSpaceXform>(steps);
}
sk_sp<GrColorSpaceXform> GrColorSpaceXform::Make(const GrColorInfo& srcInfo,
const GrColorInfo& dstInfo) {
return Make(srcInfo.colorSpace(), srcInfo.alphaType(),
dstInfo.colorSpace(), dstInfo.alphaType());
}
uint32_t GrColorSpaceXform::XformKey(const GrColorSpaceXform* xform) {
// Code generation depends on which steps we apply,
// and the kinds of transfer functions (if we're applying those).
if (!xform) { return 0; }
const SkColorSpaceXformSteps& steps(xform->fSteps);
uint32_t key = steps.flags.mask();
if (steps.flags.linearize) {
key |= skcms_TransferFunction_getType(&steps.srcTF) << 8;
}
if (steps.flags.encode) {
key |= skcms_TransferFunction_getType(&steps.dstTFInv) << 16;
}
return key;
}
bool GrColorSpaceXform::Equals(const GrColorSpaceXform* a, const GrColorSpaceXform* b) {
if (a == b) {
return true;
}
if (!a || !b || a->fSteps.flags.mask() != b->fSteps.flags.mask()) {
return false;
}
if (a->fSteps.flags.linearize &&
0 != memcmp(&a->fSteps.srcTF, &b->fSteps.srcTF, sizeof(a->fSteps.srcTF))) {
return false;
}
if (a->fSteps.flags.gamut_transform &&
0 != memcmp(&a->fSteps.src_to_dst_matrix, &b->fSteps.src_to_dst_matrix,
sizeof(a->fSteps.src_to_dst_matrix))) {
return false;
}
if (a->fSteps.flags.encode &&
0 != memcmp(&a->fSteps.dstTFInv, &b->fSteps.dstTFInv, sizeof(a->fSteps.dstTFInv))) {
return false;
}
return true;
}
SkColor4f GrColorSpaceXform::apply(const SkColor4f& srcColor) {
SkColor4f result = srcColor;
fSteps.apply(result.vec());
return result;
}
//////////////////////////////////////////////////////////////////////////////
GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProcessor> child,
sk_sp<GrColorSpaceXform> colorXform)
: INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get()))
, fColorXform(std::move(colorXform)) {
this->registerChild(std::move(child));
}
GrColorSpaceXformEffect::GrColorSpaceXformEffect(const GrColorSpaceXformEffect& that)
: INHERITED(that)
, fColorXform(that.fColorXform) {}
std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(*this));
}
bool GrColorSpaceXformEffect::onIsEqual(const GrFragmentProcessor& s) const {
const GrColorSpaceXformEffect& other = s.cast<GrColorSpaceXformEffect>();
return GrColorSpaceXform::Equals(fColorXform.get(), other.fColorXform.get());
}
void GrColorSpaceXformEffect::onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder* b) const {
b->add32(GrColorSpaceXform::XformKey(fColorXform.get()));
}
std::unique_ptr<GrFragmentProcessor::ProgramImpl>
GrColorSpaceXformEffect::onMakeProgramImpl() const {
class Impl : public ProgramImpl {
public:
void emitCode(EmitArgs& args) override {
const GrColorSpaceXformEffect& proc = args.fFp.cast<GrColorSpaceXformEffect>();
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
fColorSpaceHelper.emitCode(uniformHandler, proc.colorXform());
SkString childColor = this->invokeChild(0, args);
SkString xformedColor;
fragBuilder->appendColorGamutXform(
&xformedColor, childColor.c_str(), &fColorSpaceHelper);
fragBuilder->codeAppendf("return %s;", xformedColor.c_str());
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& fp) override {
const GrColorSpaceXformEffect& proc = fp.cast<GrColorSpaceXformEffect>();
fColorSpaceHelper.setData(pdman, proc.colorXform());
}
GrGLSLColorSpaceXformHelper fColorSpaceHelper;
};
return std::make_unique<Impl>();
}
GrFragmentProcessor::OptimizationFlags GrColorSpaceXformEffect::OptFlags(
const GrFragmentProcessor* child) {
return ProcessorOptimizationFlags(child) & (kCompatibleWithCoverageAsAlpha_OptimizationFlag |
kPreservesOpaqueInput_OptimizationFlag |
kConstantOutputForConstantInput_OptimizationFlag);
}
SkPMColor4f GrColorSpaceXformEffect::constantOutputForConstantInput(
const SkPMColor4f& input) const {
const auto c0 = ConstantOutputForConstantInput(this->childProcessor(0), input);
return this->fColorXform->apply(c0.unpremul()).premul();
}
std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
std::unique_ptr<GrFragmentProcessor> child,
SkColorSpace* src, SkAlphaType srcAT,
SkColorSpace* dst, SkAlphaType dstAT) {
return Make(std::move(child), GrColorSpaceXform::Make(src, srcAT, dst, dstAT));
}
std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
std::unique_ptr<GrFragmentProcessor> child,
const GrColorInfo& srcInfo,
const GrColorInfo& dstInfo) {
return Make(std::move(child), GrColorSpaceXform::Make(srcInfo, dstInfo));
}
std::unique_ptr<GrFragmentProcessor> GrColorSpaceXformEffect::Make(
std::unique_ptr<GrFragmentProcessor> child,
sk_sp<GrColorSpaceXform> colorXform) {
if (!colorXform) {
return child;
}
return std::unique_ptr<GrFragmentProcessor>(new GrColorSpaceXformEffect(std::move(child),
std::move(colorXform)));
}