2015-01-14 18:49:18 +00:00
|
|
|
/*
|
|
|
|
* 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 "SkArithmeticMode_gpu.h"
|
|
|
|
|
|
|
|
#if SK_SUPPORT_GPU
|
|
|
|
#include "GrContext.h"
|
|
|
|
#include "GrFragmentProcessor.h"
|
|
|
|
#include "GrInvariantOutput.h"
|
|
|
|
#include "GrProcessor.h"
|
|
|
|
#include "GrTexture.h"
|
2015-11-13 14:54:19 +00:00
|
|
|
#include "glsl/GrGLSLFragmentProcessor.h"
|
2015-11-11 21:06:05 +00:00
|
|
|
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
2015-10-28 14:26:40 +00:00
|
|
|
#include "glsl/GrGLSLProgramDataManager.h"
|
2015-12-03 17:20:44 +00:00
|
|
|
#include "glsl/GrGLSLUniformHandler.h"
|
2015-11-13 16:34:52 +00:00
|
|
|
#include "glsl/GrGLSLXferProcessor.h"
|
2015-01-14 18:49:18 +00:00
|
|
|
|
|
|
|
static const bool gUseUnpremul = false;
|
|
|
|
|
2015-11-18 16:01:26 +00:00
|
|
|
static void add_arithmetic_code(GrGLSLFragmentBuilder* fragBuilder,
|
2015-09-15 22:33:27 +00:00
|
|
|
const char* srcColor,
|
2015-01-14 20:53:01 +00:00
|
|
|
const char* dstColor,
|
|
|
|
const char* outputColor,
|
|
|
|
const char* kUni,
|
|
|
|
bool enforcePMColor) {
|
|
|
|
// We don't try to optimize for this case at all
|
2015-09-15 22:33:27 +00:00
|
|
|
if (nullptr == srcColor) {
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppend("const vec4 src = vec4(1);");
|
2015-01-14 20:53:01 +00:00
|
|
|
} else {
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppendf("vec4 src = %s;", srcColor);
|
2015-01-14 20:53:01 +00:00
|
|
|
if (gUseUnpremul) {
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);");
|
2015-01-14 20:53:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppendf("vec4 dst = %s;", dstColor);
|
2015-01-14 20:53:01 +00:00
|
|
|
if (gUseUnpremul) {
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);");
|
2015-01-14 20:53:01 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;",
|
|
|
|
outputColor, kUni, kUni, kUni, kUni);
|
|
|
|
fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
|
2015-01-14 20:53:01 +00:00
|
|
|
if (gUseUnpremul) {
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
|
2015-01-14 20:53:01 +00:00
|
|
|
} else if (enforcePMColor) {
|
2015-11-18 16:01:26 +00:00
|
|
|
fragBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);",
|
|
|
|
outputColor, outputColor, outputColor);
|
2015-01-14 20:53:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-13 14:54:19 +00:00
|
|
|
class GLArithmeticFP : public GrGLSLFragmentProcessor {
|
2015-01-14 18:49:18 +00:00
|
|
|
public:
|
2015-07-22 22:08:53 +00:00
|
|
|
void emitCode(EmitArgs& args) override {
|
2016-02-03 20:25:40 +00:00
|
|
|
const GrArithmeticFP& arith = args.fFp.cast<GrArithmeticFP>();
|
|
|
|
|
2015-11-18 16:01:26 +00:00
|
|
|
GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
|
2015-09-24 13:00:00 +00:00
|
|
|
SkString dstColor("dstColor");
|
|
|
|
this->emitChild(0, nullptr, &dstColor, args);
|
2015-01-14 20:53:01 +00:00
|
|
|
|
2016-02-11 20:49:47 +00:00
|
|
|
fKUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
|
2015-12-03 17:20:44 +00:00
|
|
|
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
|
|
|
"k");
|
|
|
|
const char* kUni = args.fUniformHandler->getUniformCStr(fKUni);
|
2015-01-14 20:53:01 +00:00
|
|
|
|
2015-11-18 16:01:26 +00:00
|
|
|
add_arithmetic_code(fragBuilder,
|
|
|
|
args.fInputColor,
|
|
|
|
dstColor.c_str(),
|
|
|
|
args.fOutputColor,
|
|
|
|
kUni,
|
2016-02-03 20:25:40 +00:00
|
|
|
arith.enforcePMColor());
|
2015-01-14 20:53:01 +00:00
|
|
|
}
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2016-02-04 14:11:53 +00:00
|
|
|
static void GenKey(const GrProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
|
2015-01-14 20:53:01 +00:00
|
|
|
const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
|
|
|
|
uint32_t key = arith.enforcePMColor() ? 1 : 0;
|
|
|
|
b->add32(key);
|
|
|
|
}
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2015-08-18 18:29:31 +00:00
|
|
|
protected:
|
2015-10-28 14:26:40 +00:00
|
|
|
void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
|
2015-08-18 18:29:31 +00:00
|
|
|
const GrArithmeticFP& arith = proc.cast<GrArithmeticFP>();
|
|
|
|
pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
|
|
|
|
}
|
|
|
|
|
2015-01-14 18:49:18 +00:00
|
|
|
private:
|
2015-10-28 14:26:40 +00:00
|
|
|
GrGLSLProgramDataManager::UniformHandle fKUni;
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2015-11-13 14:54:19 +00:00
|
|
|
typedef GrGLSLFragmentProcessor INHERITED;
|
2015-01-14 18:49:18 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-10-06 15:40:50 +00:00
|
|
|
GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor,
|
|
|
|
const GrFragmentProcessor* dst)
|
2015-01-14 18:49:18 +00:00
|
|
|
: fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
|
|
|
|
this->initClassID<GrArithmeticFP>();
|
2015-01-14 20:53:01 +00:00
|
|
|
|
2015-09-15 22:33:27 +00:00
|
|
|
SkASSERT(dst);
|
|
|
|
SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
|
|
|
|
SkASSERT(0 == dstIndex);
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-11-13 19:57:27 +00:00
|
|
|
void GrArithmeticFP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
|
2015-01-14 18:49:18 +00:00
|
|
|
GLArithmeticFP::GenKey(*this, caps, b);
|
|
|
|
}
|
|
|
|
|
2015-11-13 19:57:27 +00:00
|
|
|
GrGLSLFragmentProcessor* GrArithmeticFP::onCreateGLSLInstance() const {
|
2016-02-03 20:25:40 +00:00
|
|
|
return new GLArithmeticFP;
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool GrArithmeticFP::onIsEqual(const GrFragmentProcessor& fpBase) const {
|
|
|
|
const GrArithmeticFP& fp = fpBase.cast<GrArithmeticFP>();
|
|
|
|
return fK1 == fp.fK1 &&
|
|
|
|
fK2 == fp.fK2 &&
|
|
|
|
fK3 == fp.fK3 &&
|
|
|
|
fK4 == fp.fK4 &&
|
|
|
|
fEnforcePMColor == fp.fEnforcePMColor;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
|
|
|
|
// TODO: optimize this
|
|
|
|
inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
|
|
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-08-29 01:46:56 +00:00
|
|
|
const GrFragmentProcessor* GrArithmeticFP::TestCreate(GrProcessorTestData* d) {
|
2015-07-08 21:26:19 +00:00
|
|
|
float k1 = d->fRandom->nextF();
|
|
|
|
float k2 = d->fRandom->nextF();
|
|
|
|
float k3 = d->fRandom->nextF();
|
|
|
|
float k4 = d->fRandom->nextF();
|
|
|
|
bool enforcePMColor = d->fRandom->nextBool();
|
|
|
|
|
2015-09-15 22:33:27 +00:00
|
|
|
SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
|
2015-10-06 15:40:50 +00:00
|
|
|
return new GrArithmeticFP(k1, k2, k3, k4, enforcePMColor, dst);
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-01-14 20:53:01 +00:00
|
|
|
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2015-01-14 20:53:01 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Xfer Processor
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2015-02-09 15:51:00 +00:00
|
|
|
class ArithmeticXP : public GrXferProcessor {
|
|
|
|
public:
|
2015-06-08 22:11:04 +00:00
|
|
|
ArithmeticXP(const DstTexture*, bool hasMixedSamples,
|
|
|
|
float k1, float k2, float k3, float k4, bool enforcePMColor);
|
2015-02-09 15:51:00 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
const char* name() const override { return "Arithmetic"; }
|
2015-02-09 15:51:00 +00:00
|
|
|
|
2015-11-13 19:57:27 +00:00
|
|
|
GrGLSLXferProcessor* createGLSLInstance() const override;
|
2015-02-09 15:51:00 +00:00
|
|
|
|
|
|
|
float k1() const { return fK1; }
|
|
|
|
float k2() const { return fK2; }
|
|
|
|
float k3() const { return fK3; }
|
|
|
|
float k4() const { return fK4; }
|
|
|
|
bool enforcePMColor() const { return fEnforcePMColor; }
|
|
|
|
|
|
|
|
private:
|
2015-11-30 16:57:38 +00:00
|
|
|
GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
|
2015-05-10 15:45:18 +00:00
|
|
|
bool doesStencilWrite,
|
|
|
|
GrColor* overrideColor,
|
2015-11-30 18:15:58 +00:00
|
|
|
const GrCaps& caps) const override;
|
2015-05-10 15:45:18 +00:00
|
|
|
|
2015-11-13 19:57:27 +00:00
|
|
|
void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
|
2015-02-09 15:51:00 +00:00
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
bool onIsEqual(const GrXferProcessor& xpBase) const override {
|
2015-02-09 15:51:00 +00:00
|
|
|
const ArithmeticXP& xp = xpBase.cast<ArithmeticXP>();
|
|
|
|
if (fK1 != xp.fK1 ||
|
|
|
|
fK2 != xp.fK2 ||
|
|
|
|
fK3 != xp.fK3 ||
|
|
|
|
fK4 != xp.fK4 ||
|
|
|
|
fEnforcePMColor != xp.fEnforcePMColor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
float fK1, fK2, fK3, fK4;
|
|
|
|
bool fEnforcePMColor;
|
|
|
|
|
|
|
|
typedef GrXferProcessor INHERITED;
|
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-11-13 16:34:52 +00:00
|
|
|
class GLArithmeticXP : public GrGLSLXferProcessor {
|
2015-01-14 20:53:01 +00:00
|
|
|
public:
|
2015-10-19 21:41:11 +00:00
|
|
|
GLArithmeticXP(const ArithmeticXP& arithmeticXP)
|
|
|
|
: fEnforcePMColor(arithmeticXP.enforcePMColor()) {
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 01:17:31 +00:00
|
|
|
~GLArithmeticXP() override {}
|
2015-01-14 20:53:01 +00:00
|
|
|
|
2015-04-28 15:48:20 +00:00
|
|
|
static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
|
2015-02-06 15:02:37 +00:00
|
|
|
GrProcessorKeyBuilder* b) {
|
2015-02-09 15:51:00 +00:00
|
|
|
const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
|
2015-02-06 15:02:37 +00:00
|
|
|
uint32_t key = arith.enforcePMColor() ? 1 : 0;
|
|
|
|
b->add32(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2015-12-03 17:20:44 +00:00
|
|
|
void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
|
|
|
|
GrGLSLUniformHandler* uniformHandler,
|
2015-11-18 16:01:26 +00:00
|
|
|
const char* srcColor,
|
2015-12-01 21:54:06 +00:00
|
|
|
const char* srcCoverage,
|
2015-11-18 16:01:26 +00:00
|
|
|
const char* dstColor,
|
|
|
|
const char* outColor,
|
2015-12-01 21:54:06 +00:00
|
|
|
const char* outColorSecondary,
|
2015-11-18 16:01:26 +00:00
|
|
|
const GrXferProcessor& proc) override {
|
2016-02-11 20:49:47 +00:00
|
|
|
fKUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
|
2015-12-03 17:20:44 +00:00
|
|
|
kVec4f_GrSLType, kDefault_GrSLPrecision,
|
|
|
|
"k");
|
|
|
|
const char* kUni = uniformHandler->getUniformCStr(fKUni);
|
2015-01-14 20:53:01 +00:00
|
|
|
|
2015-11-18 16:01:26 +00:00
|
|
|
add_arithmetic_code(fragBuilder, srcColor, dstColor, outColor, kUni, fEnforcePMColor);
|
2015-12-01 21:54:06 +00:00
|
|
|
|
|
|
|
// Apply coverage.
|
2016-01-27 13:00:04 +00:00
|
|
|
INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
|
|
|
|
outColorSecondary, proc);
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-10-28 14:26:40 +00:00
|
|
|
void onSetData(const GrGLSLProgramDataManager& pdman,
|
2015-03-26 01:17:31 +00:00
|
|
|
const GrXferProcessor& processor) override {
|
2015-02-09 15:51:00 +00:00
|
|
|
const ArithmeticXP& arith = processor.cast<ArithmeticXP>();
|
2015-01-14 20:53:01 +00:00
|
|
|
pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4());
|
|
|
|
fEnforcePMColor = arith.enforcePMColor();
|
|
|
|
};
|
|
|
|
|
2015-10-28 14:26:40 +00:00
|
|
|
GrGLSLProgramDataManager::UniformHandle fKUni;
|
2015-01-14 20:53:01 +00:00
|
|
|
bool fEnforcePMColor;
|
|
|
|
|
2015-11-13 16:34:52 +00:00
|
|
|
typedef GrGLSLXferProcessor INHERITED;
|
2015-01-14 20:53:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2015-06-08 22:11:04 +00:00
|
|
|
ArithmeticXP::ArithmeticXP(const DstTexture* dstTexture, bool hasMixedSamples,
|
|
|
|
float k1, float k2, float k3, float k4, bool enforcePMColor)
|
|
|
|
: INHERITED(dstTexture, true, hasMixedSamples)
|
2015-02-06 15:02:37 +00:00
|
|
|
, fK1(k1)
|
2015-01-14 20:53:01 +00:00
|
|
|
, fK2(k2)
|
|
|
|
, fK3(k3)
|
|
|
|
, fK4(k4)
|
|
|
|
, fEnforcePMColor(enforcePMColor) {
|
2015-02-09 15:51:00 +00:00
|
|
|
this->initClassID<ArithmeticXP>();
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-11-13 19:57:27 +00:00
|
|
|
void ArithmeticXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
|
2015-01-14 20:53:01 +00:00
|
|
|
GLArithmeticXP::GenKey(*this, caps, b);
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-11-13 19:57:27 +00:00
|
|
|
GrGLSLXferProcessor* ArithmeticXP::createGLSLInstance() const { return new GLArithmeticXP(*this); }
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2015-11-30 16:57:38 +00:00
|
|
|
GrXferProcessor::OptFlags ArithmeticXP::onGetOptimizations(
|
|
|
|
const GrPipelineOptimizations& optimizations,
|
|
|
|
bool doesStencilWrite,
|
|
|
|
GrColor* overrideColor,
|
2015-11-30 18:15:58 +00:00
|
|
|
const GrCaps& caps) const {
|
2015-07-08 18:26:37 +00:00
|
|
|
return GrXferProcessor::kNone_OptFlags;
|
2015-01-14 20:53:01 +00:00
|
|
|
}
|
2015-01-14 18:49:18 +00:00
|
|
|
|
2015-01-14 20:53:01 +00:00
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4,
|
2015-10-19 21:41:11 +00:00
|
|
|
bool enforcePMColor)
|
2015-01-14 20:53:01 +00:00
|
|
|
: fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
|
2015-01-16 14:29:47 +00:00
|
|
|
this->initClassID<GrArithmeticXPFactory>();
|
2015-01-14 18:49:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-09 15:51:00 +00:00
|
|
|
GrXferProcessor*
|
2015-05-19 16:29:46 +00:00
|
|
|
GrArithmeticXPFactory::onCreateXferProcessor(const GrCaps& caps,
|
2015-11-30 16:57:38 +00:00
|
|
|
const GrPipelineOptimizations& optimizations,
|
2015-06-08 22:11:04 +00:00
|
|
|
bool hasMixedSamples,
|
2015-05-26 16:49:05 +00:00
|
|
|
const DstTexture* dstTexture) const {
|
2015-08-26 20:07:48 +00:00
|
|
|
return new ArithmeticXP(dstTexture, hasMixedSamples, fK1, fK2, fK3, fK4, fEnforcePMColor);
|
2015-02-09 15:51:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-02 17:43:39 +00:00
|
|
|
void GrArithmeticXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
|
|
|
|
InvariantBlendedColor* blendedColor) const {
|
|
|
|
blendedColor->fWillBlendWithDst = true;
|
|
|
|
|
|
|
|
// TODO: We could try to optimize this more. For example if fK1 and fK3 are zero, then we won't
|
|
|
|
// be blending the color with dst at all so we can know what the output color is (up to the
|
|
|
|
// valid color components passed in).
|
|
|
|
blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
|
2015-01-14 20:53:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory);
|
|
|
|
|
2015-08-29 01:46:56 +00:00
|
|
|
const GrXPFactory* GrArithmeticXPFactory::TestCreate(GrProcessorTestData* d) {
|
2015-07-08 21:26:19 +00:00
|
|
|
float k1 = d->fRandom->nextF();
|
|
|
|
float k2 = d->fRandom->nextF();
|
|
|
|
float k3 = d->fRandom->nextF();
|
|
|
|
float k4 = d->fRandom->nextF();
|
|
|
|
bool enforcePMColor = d->fRandom->nextBool();
|
2015-01-14 20:53:01 +00:00
|
|
|
|
|
|
|
return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor);
|
|
|
|
}
|
2015-01-14 18:49:18 +00:00
|
|
|
|
|
|
|
#endif
|