blob: d3eaee338d295643ca6ae77f8f5cc6c45aadde73 [file] [log] [blame]
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "effects/GrXfermodeFragmentProcessor.h"
#include "GrFragmentProcessor.h"
#include "GrInvariantOutput.h"
#include "effects/GrConstColorProcessor.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLBlend.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "SkGrPriv.h"
class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
public:
ComposeTwoFragmentProcessor(sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst,
SkBlendMode mode)
: fMode(mode) {
this->initClassID<ComposeTwoFragmentProcessor>();
SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src));
SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst));
SkASSERT(0 == shaderAChildIndex);
SkASSERT(1 == shaderBChildIndex);
}
const char* name() const override { return "ComposeTwo"; }
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
b->add32((int)fMode);
}
SkBlendMode getMode() const { return fMode; }
protected:
bool onIsEqual(const GrFragmentProcessor& other) const override {
const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
return fMode == cs.fMode;
}
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
}
private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
SkBlendMode fMode;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
typedef GrFragmentProcessor INHERITED;
};
/////////////////////////////////////////////////////////////////////
class GLComposeTwoFragmentProcessor : public GrGLSLFragmentProcessor {
public:
void emitCode(EmitArgs&) override;
private:
typedef GrGLSLFragmentProcessor INHERITED;
};
/////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
sk_sp<GrFragmentProcessor> ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
// Create two random frag procs.
sk_sp<GrFragmentProcessor> fpA(GrProcessorUnitTest::MakeChildFP(d));
sk_sp<GrFragmentProcessor> fpB(GrProcessorUnitTest::MakeChildFP(d));
SkBlendMode mode = static_cast<SkBlendMode>(
d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
return sk_sp<GrFragmentProcessor>(
new ComposeTwoFragmentProcessor(std::move(fpA), std::move(fpB), mode));
}
GrGLSLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLSLInstance() const{
return new GLComposeTwoFragmentProcessor;
}
/////////////////////////////////////////////////////////////////////
void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
const char* inputColor = nullptr;
if (args.fInputColor) {
inputColor = "inputColor";
fragBuilder->codeAppendf("vec4 inputColor = vec4(%s.rgb, 1.0);", args.fInputColor);
}
// declare outputColor and emit the code for each of the two children
SkString srcColor("xfer_src");
this->emitChild(0, inputColor, &srcColor, args);
SkString dstColor("xfer_dst");
this->emitChild(1, inputColor, &dstColor, args);
// emit blend code
SkBlendMode mode = cs.getMode();
fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
GrGLSLBlend::AppendMode(fragBuilder,
srcColor.c_str(),
dstColor.c_str(),
args.fOutputColor,
mode);
// re-multiply the output color by the input color's alpha
if (args.fInputColor) {
fragBuilder->codeAppendf("%s *= %s.a;", args.fOutputColor, args.fInputColor);
}
}
sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoProcessors(
sk_sp<GrFragmentProcessor> src, sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kClear:
return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
GrConstColorProcessor::kIgnore_InputMode);
case SkBlendMode::kSrc:
return src;
case SkBlendMode::kDst:
return dst;
default:
return sk_sp<GrFragmentProcessor>(
new ComposeTwoFragmentProcessor(std::move(src), std::move(dst), mode));
}
}
//////////////////////////////////////////////////////////////////////////////
class ComposeOneFragmentProcessor : public GrFragmentProcessor {
public:
enum Child {
kDst_Child,
kSrc_Child,
};
ComposeOneFragmentProcessor(sk_sp<GrFragmentProcessor> dst, SkBlendMode mode, Child child)
: fMode(mode)
, fChild(child) {
this->initClassID<ComposeOneFragmentProcessor>();
SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(std::move(dst));
SkASSERT(0 == dstIndex);
}
const char* name() const override { return "ComposeOne"; }
SkString dumpInfo() const override {
SkString str;
for (int i = 0; i < this->numChildProcessors(); ++i) {
str.append(this->childProcessor(i).dumpInfo());
}
return str;
}
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
GR_STATIC_ASSERT(((int)SkBlendMode::kLastMode & SK_MaxU16) == (int)SkBlendMode::kLastMode);
b->add32((int)fMode | (fChild << 16));
}
SkBlendMode mode() const { return fMode; }
Child child() const { return fChild; }
protected:
bool onIsEqual(const GrFragmentProcessor& that) const override {
return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
}
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
SkXfermode::Coeff skSrcCoeff, skDstCoeff;
if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) {
GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff);
GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff);
GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags);
this->childProcessor(0).computeInvariantOutput(&childOutput);
GrColor blendColor;
GrColorComponentFlags blendFlags;
if (kDst_Child == fChild) {
GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
inout->color(), inout->validFlags(),
childOutput.color(), childOutput.validFlags(),
&blendColor, &blendFlags);
} else {
GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
childOutput.color(), childOutput.validFlags(),
inout->color(), inout->validFlags(),
&blendColor, &blendFlags);
}
// will the shader code reference the input color?
GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput;
if (kDst_Child == fChild) {
if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) {
readsInput = GrInvariantOutput::kWill_ReadInput;
}
} else {
if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) {
readsInput = GrInvariantOutput::kWill_ReadInput;
}
}
inout->setToOther(blendFlags, blendColor, readsInput);
} else {
inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
}
}
private:
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
SkBlendMode fMode;
Child fChild;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
typedef GrFragmentProcessor INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
class GLComposeOneFragmentProcessor : public GrGLSLFragmentProcessor {
public:
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
SkBlendMode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
ComposeOneFragmentProcessor::Child child =
args.fFp.cast<ComposeOneFragmentProcessor>().child();
SkString childColor("child");
this->emitChild(0, nullptr, &childColor, args);
const char* inputColor = args.fInputColor;
// We don't try to optimize for this case at all
if (!inputColor) {
fragBuilder->codeAppendf("const vec4 ones = vec4(1);");
inputColor = "ones";
}
// emit blend code
fragBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
const char* childStr = childColor.c_str();
if (ComposeOneFragmentProcessor::kDst_Child == child) {
GrGLSLBlend::AppendMode(fragBuilder, inputColor, childStr, args.fOutputColor, mode);
} else {
GrGLSLBlend::AppendMode(fragBuilder, childStr, inputColor, args.fOutputColor, mode);
}
}
private:
typedef GrGLSLFragmentProcessor INHERITED;
};
/////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
sk_sp<GrFragmentProcessor> ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
// Create one random frag procs.
// For now, we'll prevent either children from being a shader with children to prevent the
// possibility of an arbitrarily large tree of procs.
sk_sp<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d));
SkBlendMode mode = static_cast<SkBlendMode>(
d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode));
ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ?
ComposeOneFragmentProcessor::kDst_Child :
ComposeOneFragmentProcessor::kSrc_Child;
return sk_sp<GrFragmentProcessor>(new ComposeOneFragmentProcessor(std::move(dst), mode, child));
}
GrGLSLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLSLInstance() const {
return new GLComposeOneFragmentProcessor;
}
//////////////////////////////////////////////////////////////////////////////
sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstProcessor(
sk_sp<GrFragmentProcessor> dst, SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kClear:
return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
GrConstColorProcessor::kIgnore_InputMode);
case SkBlendMode::kSrc:
return nullptr;
default:
return sk_sp<GrFragmentProcessor>(
new ComposeOneFragmentProcessor(std::move(dst), mode,
ComposeOneFragmentProcessor::kDst_Child));
}
}
sk_sp<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcProcessor(
sk_sp<GrFragmentProcessor> src, SkBlendMode mode) {
switch (mode) {
case SkBlendMode::kClear:
return GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
GrConstColorProcessor::kIgnore_InputMode);
case SkBlendMode::kDst:
return nullptr;
default:
return sk_sp<GrFragmentProcessor>(
new ComposeOneFragmentProcessor(src, mode,
ComposeOneFragmentProcessor::kSrc_Child));
}
}