From f351aa3bf1b1d7639be8e1e6a35137b89a8dd93d Mon Sep 17 00:00:00 2001 From: egdaniel Date: Wed, 14 Jan 2015 12:53:01 -0800 Subject: Add Arithmetic mode xp. BUG=skia: Review URL: https://codereview.chromium.org/837633005 --- src/effects/SkArithmeticMode.cpp | 16 ++- src/effects/SkArithmeticMode_gpu.cpp | 268 ++++++++++++++++++++++++----------- src/effects/SkArithmeticMode_gpu.h | 121 +++++++++++++++- src/gpu/GrOptDrawState.cpp | 4 + src/gpu/GrProcessor.cpp | 2 +- 5 files changed, 320 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp index d86f73bee4..ae18c2770e 100644 --- a/src/effects/SkArithmeticMode.cpp +++ b/src/effects/SkArithmeticMode.cpp @@ -31,8 +31,9 @@ public: SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar) #if SK_SUPPORT_GPU - virtual bool asFragmentProcessor(GrFragmentProcessor**, - GrTexture* background) const SK_OVERRIDE; + bool asFragmentProcessor(GrFragmentProcessor**, GrTexture* background) const SK_OVERRIDE; + + bool asXPFactory(GrXPFactory**) const SK_OVERRIDE; #endif private: @@ -246,6 +247,17 @@ bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp, return true; } +bool SkArithmeticMode_scalar::asXPFactory(GrXPFactory** xpf) const { + if (xpf) { + *xpf = GrArithmeticXPFactory::Create(SkScalarToFloat(fK[0]), + SkScalarToFloat(fK[1]), + SkScalarToFloat(fK[2]), + SkScalarToFloat(fK[3]), + fEnforcePMColor); + } + return true; +} + #endif SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkArithmeticMode) diff --git a/src/effects/SkArithmeticMode_gpu.cpp b/src/effects/SkArithmeticMode_gpu.cpp index 6ccd63ba74..3209fb9214 100644 --- a/src/effects/SkArithmeticMode_gpu.cpp +++ b/src/effects/SkArithmeticMode_gpu.cpp @@ -20,21 +20,77 @@ static const bool gUseUnpremul = false; +static void add_arithmetic_code(GrGLFPFragmentBuilder* fsBuilder, + const char* inputColor, + const char* dstColor, + const char* outputColor, + const char* kUni, + bool enforcePMColor) { + // We don't try to optimize for this case at all + if (NULL == inputColor) { + fsBuilder->codeAppend("const vec4 src = vec4(1);"); + } else { + fsBuilder->codeAppendf("vec4 src = %s;", inputColor); + if (gUseUnpremul) { + fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);"); + } + } + + fsBuilder->codeAppendf("vec4 dst = %s;", dstColor); + if (gUseUnpremul) { + fsBuilder->codeAppend("dst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);"); + } + + fsBuilder->codeAppendf("%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;", + outputColor, kUni, kUni, kUni, kUni); + fsBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); + if (gUseUnpremul) { + fsBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor); + } else if (enforcePMColor) { + fsBuilder->codeAppendf("%s.rgb = min(%s.rgb, %s.a);", + outputColor, outputColor, outputColor); + } +} + class GLArithmeticFP : public GrGLFragmentProcessor { public: - GLArithmeticFP(const GrProcessor&); - virtual ~GLArithmeticFP(); + GLArithmeticFP(const GrProcessor&) + : fEnforcePMColor(true) { + } - virtual void emitCode(GrGLFPBuilder*, - const GrFragmentProcessor&, - const char* outputColor, - const char* inputColor, - const TransformedCoordsArray&, - const TextureSamplerArray&) SK_OVERRIDE; + ~GLArithmeticFP() SK_OVERRIDE {} + + void emitCode(GrGLFPBuilder* builder, + const GrFragmentProcessor& fp, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray& coords, + const TextureSamplerArray& samplers) SK_OVERRIDE { + GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); + fsBuilder->codeAppend("vec4 bgColor = "); + fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); + fsBuilder->codeAppendf(";"); + const char* dstColor = "bgColor"; + + fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "k"); + const char* kUni = builder->getUniformCStr(fKUni); + + add_arithmetic_code(fsBuilder, inputColor, dstColor, outputColor, kUni, fEnforcePMColor); + } - virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; + void setData(const GrGLProgramDataManager& pdman, const GrProcessor& proc) SK_OVERRIDE { + const GrArithmeticFP& arith = proc.cast(); + pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); + fEnforcePMColor = arith.enforcePMColor(); + } - static void GenKey(const GrProcessor&, const GrGLCaps& caps, GrProcessorKeyBuilder* b); + static void GenKey(const GrProcessor& proc, const GrGLCaps& caps, GrProcessorKeyBuilder* b) { + const GrArithmeticFP& arith = proc.cast(); + uint32_t key = arith.enforcePMColor() ? 1 : 0; + b->add32(key); + } private: GrGLProgramDataManager::UniformHandle fKUni; @@ -49,15 +105,14 @@ GrArithmeticFP::GrArithmeticFP(float k1, float k2, float k3, float k4, bool enforcePMColor, GrTexture* background) : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { this->initClassID(); - if (background) { - fBackgroundTransform.reset(kLocal_GrCoordSet, background, - GrTextureParams::kNone_FilterMode); - this->addCoordTransform(&fBackgroundTransform); - fBackgroundAccess.reset(background); - this->addTextureAccess(&fBackgroundAccess); - } else { - this->setWillReadDstColor(); - } + + SkASSERT(background); + + fBackgroundTransform.reset(kLocal_GrCoordSet, background, + GrTextureParams::kNone_FilterMode); + this->addCoordTransform(&fBackgroundTransform); + fBackgroundAccess.reset(background); + this->addTextureAccess(&fBackgroundAccess); } void GrArithmeticFP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const { @@ -84,91 +139,132 @@ void GrArithmeticFP::onComputeInvariantOutput(GrInvariantOutput* inout) const { /////////////////////////////////////////////////////////////////////////////// -GLArithmeticFP::GLArithmeticFP(const GrProcessor&) - : fEnforcePMColor(true) { -} +GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand, + GrContext*, + const GrDrawTargetCaps&, + GrTexture* textures[]) { + float k1 = rand->nextF(); + float k2 = rand->nextF(); + float k3 = rand->nextF(); + float k4 = rand->nextF(); + bool enforcePMColor = rand->nextBool(); -GLArithmeticFP::~GLArithmeticFP() { + return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, textures[0])); } -void GLArithmeticFP::emitCode(GrGLFPBuilder* builder, - const GrFragmentProcessor& fp, - const char* outputColor, - const char* inputColor, - const TransformedCoordsArray& coords, - const TextureSamplerArray& samplers) { - - GrTexture* backgroundTex = fp.cast().backgroundTexture(); - GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder(); - const char* dstColor; - if (backgroundTex) { - fsBuilder->codeAppend("\t\tvec4 bgColor = "); - fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].getType()); - fsBuilder->codeAppendf(";\n"); - dstColor = "bgColor"; - } else { - dstColor = fsBuilder->dstColor(); - } +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); - SkASSERT(dstColor); - fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, - kVec4f_GrSLType, kDefault_GrSLPrecision, - "k"); - const char* kUni = builder->getUniformCStr(fKUni); +/////////////////////////////////////////////////////////////////////////////// +// Xfer Processor +/////////////////////////////////////////////////////////////////////////////// - // We don't try to optimize for this case at all - if (NULL == inputColor) { - fsBuilder->codeAppendf("\t\tconst vec4 src = vec4(1);\n"); - } else { - fsBuilder->codeAppendf("\t\tvec4 src = %s;\n", inputColor); - if (gUseUnpremul) { - fsBuilder->codeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.0);\n"); - } +class GLArithmeticXP : public GrGLXferProcessor { +public: + GLArithmeticXP(const GrProcessor&) + : fEnforcePMColor(true) { } - fsBuilder->codeAppendf("\t\tvec4 dst = %s;\n", dstColor); - if (gUseUnpremul) { - fsBuilder->codeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\n"); + ~GLArithmeticXP() SK_OVERRIDE {} + + void emitCode(const EmitArgs& args) SK_OVERRIDE { + GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); + + const char* dstColor = fsBuilder->dstColor(); + + fKUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, + kVec4f_GrSLType, kDefault_GrSLPrecision, + "k"); + const char* kUni = args.fPB->getUniformCStr(fKUni); + + add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputPrimary, kUni, + fEnforcePMColor); + + fsBuilder->codeAppendf("%s = %s * %s + (vec4(1.0) - %s) * %s;", + args.fOutputPrimary, args.fOutputPrimary, args.fInputCoverage, + args.fInputCoverage, dstColor); } - fsBuilder->codeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;\n", outputColor, kUni, kUni, kUni, kUni); - fsBuilder->codeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor); - if (gUseUnpremul) { - fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); - } else if (fEnforcePMColor) { - fsBuilder->codeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor, outputColor, outputColor); + void setData(const GrGLProgramDataManager& pdman, + const GrXferProcessor& processor) SK_OVERRIDE { + const GrArithmeticXP& arith = processor.cast(); + pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); + fEnforcePMColor = arith.enforcePMColor(); + }; + + static void GenKey(const GrProcessor& processor, const GrGLCaps& caps, + GrProcessorKeyBuilder* b) { + const GrArithmeticXP& arith = processor.cast(); + uint32_t key = arith.enforcePMColor() ? 1 : 0; + b->add32(key); } + +private: + GrGLProgramDataManager::UniformHandle fKUni; + bool fEnforcePMColor; + + typedef GrGLXferProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrArithmeticXP::GrArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor) + : fK1(k1) + , fK2(k2) + , fK3(k3) + , fK4(k4) + , fEnforcePMColor(enforcePMColor) { + this->initClassID(); + this->setWillReadDstColor(); } -void GLArithmeticFP::setData(const GrGLProgramDataManager& pdman, const GrProcessor& processor) { - const GrArithmeticFP& arith = processor.cast(); - pdman.set4f(fKUni, arith.k1(), arith.k2(), arith.k3(), arith.k4()); - fEnforcePMColor = arith.enforcePMColor(); +void GrArithmeticXP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const { + GLArithmeticXP::GenKey(*this, caps, b); } -void GLArithmeticFP::GenKey(const GrProcessor& processor, const GrGLCaps&, - GrProcessorKeyBuilder* b) { - const GrArithmeticFP& arith = processor.cast(); - uint32_t key = arith.enforcePMColor() ? 1 : 0; - if (arith.backgroundTexture()) { - key |= 2; - } - b->add32(key); +GrGLXferProcessor* GrArithmeticXP::createGLInstance() const { + return SkNEW_ARGS(GLArithmeticXP, (*this)); } -GrFragmentProcessor* GrArithmeticFP::TestCreate(SkRandom* rand, - GrContext*, - const GrDrawTargetCaps&, - GrTexture*[]) { - float k1 = rand->nextF(); - float k2 = rand->nextF(); - float k3 = rand->nextF(); - float k4 = rand->nextF(); - bool enforcePMColor = rand->nextBool(); +GrXferProcessor::OptFlags GrArithmeticXP::getOptimizations(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool doesStencilWrite, + GrColor* overrideColor, + const GrDrawTargetCaps& caps) { + return GrXferProcessor::kNone_Opt; +} - return SkNEW_ARGS(GrArithmeticFP, (k1, k2, k3, k4, enforcePMColor, NULL)); +/////////////////////////////////////////////////////////////////////////////// + +GrArithmeticXPFactory::GrArithmeticXPFactory(float k1, float k2, float k3, float k4, + bool enforcePMColor) + : fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) { + this->initClassID(); } -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP); +void GrArithmeticXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + GrXPFactory::InvariantOutput* output) const { + output->fWillBlendWithDst = true; + + // TODO: We could try to optimize this more. For example if we have solid coverage and 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). + output->fBlendedColorFlags = 0; +} + +GR_DEFINE_XP_FACTORY_TEST(GrArithmeticXPFactory); + +GrXPFactory* GrArithmeticXPFactory::TestCreate(SkRandom* random, + GrContext*, + const GrDrawTargetCaps&, + GrTexture*[]) { + float k1 = random->nextF(); + float k2 = random->nextF(); + float k3 = random->nextF(); + float k4 = random->nextF(); + bool enforcePMColor = random->nextBool(); + + return GrArithmeticXPFactory::Create(k1, k2, k3, k4, enforcePMColor); +} #endif diff --git a/src/effects/SkArithmeticMode_gpu.h b/src/effects/SkArithmeticMode_gpu.h index 84b839d2cb..17116c29be 100644 --- a/src/effects/SkArithmeticMode_gpu.h +++ b/src/effects/SkArithmeticMode_gpu.h @@ -13,8 +13,11 @@ #include "GrCoordTransform.h" #include "GrFragmentProcessor.h" #include "GrTextureAccess.h" +#include "GrTypes.h" +#include "GrXferProcessor.h" class GrInvariantOutput; +class GrProcOptInfo; class GrTexture; /////////////////////////////////////////////////////////////////////////////// @@ -38,8 +41,6 @@ public: GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE; - GrTexture* backgroundTexture() const { return fBackgroundAccess.getTexture(); } - float k1() const { return fK1; } float k2() const { return fK2; } float k3() const { return fK3; } @@ -63,5 +64,121 @@ private: typedef GrFragmentProcessor INHERITED; }; +/////////////////////////////////////////////////////////////////////////////// +// Xfer Processor +/////////////////////////////////////////////////////////////////////////////// + +class GrArithmeticXP : public GrXferProcessor { +public: + static GrXferProcessor* Create(float k1, float k2, float k3, float k4, bool enforcePMColor) { + return SkNEW_ARGS(GrArithmeticXP, (k1, k2, k3, k4, enforcePMColor)); + } + + ~GrArithmeticXP() SK_OVERRIDE {}; + + const char* name() const SK_OVERRIDE { return "Arithmetic"; } + + void getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE; + + GrGLXferProcessor* createGLInstance() const SK_OVERRIDE; + + bool hasSecondaryOutput() const SK_OVERRIDE { return false; } + + GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool doesStencilWrite, + GrColor* overrideColor, + const GrDrawTargetCaps& caps) SK_OVERRIDE; + + void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE { + blendInfo->fSrcBlend = kOne_GrBlendCoeff; + blendInfo->fDstBlend = kZero_GrBlendCoeff; + blendInfo->fBlendConstant = 0; + } + + 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: + GrArithmeticXP(float k1, float k2, float k3, float k4, bool enforcePMColor); + + bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE { + const GrArithmeticXP& xp = xpBase.cast(); + 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; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class GrArithmeticXPFactory : public GrXPFactory { +public: + static GrXPFactory* Create(float k1, float k2, float k3, float k4, bool enforcePMColor) { + return SkNEW_ARGS(GrArithmeticXPFactory, (k1, k2, k3, k4, enforcePMColor)); + } + + GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI) const SK_OVERRIDE { + return GrArithmeticXP::Create(fK1, fK2, fK3, fK4, fEnforcePMColor); + } + + bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE { + return true; + } + + bool canApplyCoverage(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI) const SK_OVERRIDE { + return true; + } + + bool canTweakAlphaForCoverage() const SK_OVERRIDE { + return false; + } + + void getInvariantOutput(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, + GrXPFactory::InvariantOutput*) const SK_OVERRIDE; + + bool willReadDst(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI) const SK_OVERRIDE { + return true; + } + +private: + GrArithmeticXPFactory(float k1, float k2, float k3, float k4, bool enforcePMColor); + + bool onIsEqual(const GrXPFactory& xpfBase) const SK_OVERRIDE { + const GrArithmeticXPFactory& xpf = xpfBase.cast(); + if (fK1 != xpf.fK1 || + fK2 != xpf.fK2 || + fK3 != xpf.fK3 || + fK4 != xpf.fK4 || + fEnforcePMColor != xpf.fEnforcePMColor) { + return false; + } + return true; + } + + GR_DECLARE_XP_FACTORY_TEST; + + float fK1, fK2, fK3, fK4; + bool fEnforcePMColor; + + typedef GrXPFactory INHERITED; +}; + #endif #endif diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp index a30121256d..742ffade12 100644 --- a/src/gpu/GrOptDrawState.cpp +++ b/src/gpu/GrOptDrawState.cpp @@ -145,6 +145,10 @@ void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds, fDescInfo.fReadsFragPosition = true; } } + + if (fXferProcessor->willReadDstColor()) { + fDescInfo.fReadsDst = true; + } } void GrOptDrawState::finalize(GrGpu* gpu) { diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index 75245f34ae..44c8bf1957 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -52,7 +52,7 @@ GrProcessorTestFactory::GetFactories() { */ static const int kFPFactoryCount = 37; static const int kGPFactoryCount = 14; -static const int kXPFactoryCount = 3; +static const int kXPFactoryCount = 4; template<> void GrProcessorTestFactory::VerifyFactoryCount() { -- cgit v1.2.3