Make specialized SrcOver XPFactory

BUG=skia:

Review URL: https://codereview.chromium.org/1455273006
This commit is contained in:
egdaniel 2015-11-20 14:01:07 -08:00 committed by Commit bot
parent 8b78bd6d5b
commit a7006d4521
11 changed files with 173 additions and 49 deletions

View File

@ -209,13 +209,13 @@ public:
will install it and own a ref to it. Since the xfermode may or may not assign *xpf, the
caller should set *xpf to NULL beforehand. XferProcessors cannot use a background texture.
*/
virtual bool asXPFactory(GrXPFactory** xpf) const;
virtual bool asXPFactory(const GrXPFactory** xpf) const;
/** Returns true if the xfermode can be expressed as an xfer processor factory (xpFactory).
This helper calls the asXPFactory() virtual. If the xfermode is NULL, it is treated as
kSrcOver_Mode. It is legal to call this with xpf param NULL to simply test the return value.
*/
static bool AsXPFactory(SkXfermode*, GrXPFactory**);
static bool AsXPFactory(SkXfermode*, const GrXPFactory**);
SK_TO_STRING_PUREVIRT()
SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP()

View File

@ -18,7 +18,7 @@ class GrTexture;
*/
namespace GrCustomXfermode {
bool IsSupportedMode(SkXfermode::Mode mode);
GrXPFactory* CreateXPFactory(SkXfermode::Mode mode);
const GrXPFactory* CreateXPFactory(SkXfermode::Mode mode);
};
#endif

View File

@ -14,9 +14,9 @@
class GrProcOptInfo;
class GrPorterDuffXPFactory : public GrXPFactory {
class GrPDXPFactory : public GrXPFactory {
public:
static GrXPFactory* Create(SkXfermode::Mode mode);
static const GrXPFactory* Create(SkXfermode::Mode mode);
bool supportsRGBCoverage(GrColor /*knownColor*/, uint32_t /*knownColorFlags*/) const override {
return true;
@ -26,7 +26,7 @@ public:
GrXPFactory::InvariantBlendedColor*) const override;
private:
GrPorterDuffXPFactory(SkXfermode::Mode);
GrPDXPFactory(SkXfermode::Mode);
GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
@ -40,7 +40,7 @@ private:
bool hasMixedSamples) const override;
bool onIsEqual(const GrXPFactory& xpfBase) const override {
const GrPorterDuffXPFactory& xpf = xpfBase.cast<GrPorterDuffXPFactory>();
const GrPDXPFactory& xpf = xpfBase.cast<GrPDXPFactory>();
return fXfermode == xpf.fXfermode;
}
@ -53,4 +53,47 @@ private:
typedef GrXPFactory INHERITED;
};
class GrSrcOverPDXPFactory : public GrXPFactory {
public:
GrSrcOverPDXPFactory();
bool supportsRGBCoverage(GrColor /*knownColor*/, uint32_t /*knownColorFlags*/) const override {
return true;
}
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
private:
GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples,
const DstTexture*) const override;
bool willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples) const override;
bool onIsEqual(const GrXPFactory& /*xpfBase*/) const override {
return true;
}
GR_DECLARE_XP_FACTORY_TEST;
typedef GrXPFactory INHERITED;
};
namespace GrPorterDuffXPFactory {
const GrSrcOverPDXPFactory gSrcOverPDXPFactory;
inline const GrXPFactory* Create(SkXfermode::Mode mode) {
if (SkXfermode::kSrcOver_Mode == mode) {
return SkRef(&gSrcOverPDXPFactory);
}
return GrPDXPFactory::Create(mode);
}
};
#endif

View File

@ -656,7 +656,7 @@ bool SkXfermode::asFragmentProcessor(const GrFragmentProcessor**,
return false;
}
bool SkXfermode::asXPFactory(GrXPFactory**) const {
bool SkXfermode::asXPFactory(const GrXPFactory**) const {
return false;
}
@ -664,7 +664,7 @@ bool SkXfermode::asXPFactory(GrXPFactory**) const {
#if SK_SUPPORT_GPU
#include "effects/GrPorterDuffXferProcessor.h"
bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
bool SkXfermode::AsXPFactory(SkXfermode* xfermode, const GrXPFactory** xpf) {
if (nullptr == xfermode) {
if (xpf) {
*xpf = GrPorterDuffXPFactory::Create(kSrcOver_Mode);
@ -675,7 +675,7 @@ bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
}
}
#else
bool SkXfermode::AsXPFactory(SkXfermode* xfermode, GrXPFactory** xpf) {
bool SkXfermode::AsXPFactory(SkXfermode* xfermode, const GrXPFactory** xpf) {
return false;
}
#endif
@ -932,7 +932,7 @@ bool SkProcCoeffXfermode::asFragmentProcessor(const GrFragmentProcessor** fp,
return true;
}
bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const {
bool SkProcCoeffXfermode::asXPFactory(const GrXPFactory** xp) const {
if (CANNOT_USE_COEFF != fSrcCoeff) {
if (xp) {
*xp = GrPorterDuffXPFactory::Create(fMode);

View File

@ -47,7 +47,7 @@ public:
bool asFragmentProcessor(const GrFragmentProcessor**,
const GrFragmentProcessor*) const override;
bool asXPFactory(GrXPFactory**) const override;
bool asXPFactory(const GrXPFactory**) const override;
#endif
SK_TO_STRING_OVERRIDE()

View File

@ -34,7 +34,7 @@ public:
bool asFragmentProcessor(const GrFragmentProcessor**,
const GrFragmentProcessor* dst) const override;
bool asXPFactory(GrXPFactory**) const override;
bool asXPFactory(const GrXPFactory**) const override;
#endif
private:
@ -248,7 +248,7 @@ bool SkArithmeticMode_scalar::asFragmentProcessor(const GrFragmentProcessor** fp
return true;
}
bool SkArithmeticMode_scalar::asXPFactory(GrXPFactory** xpf) const {
bool SkArithmeticMode_scalar::asXPFactory(const GrXPFactory** xpf) const {
if (xpf) {
*xpf = GrArithmeticXPFactory::Create(SkScalarToFloat(fK[0]),
SkScalarToFloat(fK[1]),

View File

@ -50,7 +50,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() {
*/
static const int kFPFactoryCount = 38;
static const int kGPFactoryCount = 14;
static const int kXPFactoryCount = 5;
static const int kXPFactoryCount = 6;
template<>
void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() {

View File

@ -488,7 +488,7 @@ static inline bool skpaint_to_grpaint_impl(GrContext* context,
}
SkXfermode* mode = skPaint.getXfermode();
GrXPFactory* xpFactory = nullptr;
const GrXPFactory* xpFactory = nullptr;
if (!SkXfermode::AsXPFactory(mode, &xpFactory)) {
// Fall back to src-over
// return false here?

View File

@ -395,7 +395,7 @@ const GrXPFactory* CustomXPFactory::TestCreate(GrProcessorTestData* d) {
///////////////////////////////////////////////////////////////////////////////
GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
const GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
if (!GrCustomXfermode::IsSupportedMode(mode)) {
return nullptr;
} else {

View File

@ -691,30 +691,30 @@ PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
///////////////////////////////////////////////////////////////////////////////
GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
GrPDXPFactory::GrPDXPFactory(SkXfermode::Mode xfermode)
: fXfermode(xfermode) {
SkASSERT(fXfermode <= SkXfermode::kLastCoeffMode);
this->initClassID<GrPorterDuffXPFactory>();
this->initClassID<GrPDXPFactory>();
}
GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
const GrXPFactory* GrPDXPFactory::Create(SkXfermode::Mode xfermode) {
static const GrPDXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
static const GrPDXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
static const GrPDXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
static const GrPDXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
static const GrPDXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
static const GrPDXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
static const GrPDXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
static const GrPDXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
static const GrPDXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
static const GrPDXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
static const GrPDXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
static const GrPDXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
static const GrPDXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
static const GrPDXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
static const GrPDXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
static GrPorterDuffXPFactory* gFactories[] = {
static const GrPDXPFactory* gFactories[] = {
&gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
&gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
&gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
@ -728,7 +728,7 @@ GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
}
GrXferProcessor*
GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
GrPDXPFactory::onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& covPOI,
bool hasMixedSamples,
@ -757,7 +757,7 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
return new PorterDuffXferProcessor(blendFormula);
}
void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
void GrPDXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
InvariantBlendedColor* blendedColor) const {
// Find the blended color info based on the formula that does not have coverage.
BlendFormula colorFormula = gBlendTable[colorPOI.isOpaque()][0][fXfermode];
@ -788,7 +788,7 @@ void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorP
}
}
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
bool GrPDXPFactory::willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& covPOI,
bool hasMixedSamples) const {
@ -812,16 +812,16 @@ bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput();
}
GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
GR_DEFINE_XP_FACTORY_TEST(GrPDXPFactory);
const GrXPFactory* GrPorterDuffXPFactory::TestCreate(GrProcessorTestData* d) {
const GrXPFactory* GrPDXPFactory::TestCreate(GrProcessorTestData* d) {
SkXfermode::Mode mode = SkXfermode::Mode(d->fRandom->nextULessThan(SkXfermode::kLastCoeffMode));
return GrPorterDuffXPFactory::Create(mode);
return GrPDXPFactory::Create(mode);
}
void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
int* outPrimary,
int* outSecondary) {
void GrPDXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
int* outPrimary,
int* outSecondary) {
if (!!strcmp(xp->name(), "Porter Duff")) {
*outPrimary = *outSecondary = -1;
return;
@ -830,3 +830,84 @@ void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
*outPrimary = blendFormula.fPrimaryOutputType;
*outSecondary = blendFormula.fSecondaryOutputType;
}
////////////////////////////////////////////////////////////////////////////////
GrSrcOverPDXPFactory::GrSrcOverPDXPFactory() {
this->initClassID<GrSrcOverPDXPFactory>();
}
GrXferProcessor*
GrSrcOverPDXPFactory::onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& covPOI,
bool hasMixedSamples,
const DstTexture* dstTexture) const {
BlendFormula blendFormula;
if (covPOI.isFourChannelOutput()) {
if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
!caps.shaderCaps()->dualSourceBlendingSupport() &&
!caps.shaderCaps()->dstReadInShaderSupport()) {
// If we don't have dual source blending or in shader dst reads, we fall back to this
// trick for rendering SrcOver LCD text instead of doing a dst copy.
SkASSERT(!dstTexture || !dstTexture->texture());
return PDLCDXferProcessor::Create(SkXfermode::kSrcOver_Mode, colorPOI);
}
blendFormula = get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode);
} else {
blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples,
SkXfermode::kSrcOver_Mode);
}
if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkXfermode::kSrcOver_Mode);
}
SkASSERT(!dstTexture || !dstTexture->texture());
return new PorterDuffXferProcessor(blendFormula);
}
void GrSrcOverPDXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
InvariantBlendedColor* blendedColor) const {
if (!colorPOI.isOpaque()) {
blendedColor->fWillBlendWithDst = true;
blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
return;
}
blendedColor->fWillBlendWithDst = false;
blendedColor->fKnownColor = colorPOI.color();
blendedColor->fKnownColorFlags = colorPOI.validFlags();
}
bool GrSrcOverPDXPFactory::willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& covPOI,
bool hasMixedSamples) const {
if (caps.shaderCaps()->dualSourceBlendingSupport()) {
return false;
}
// When we have four channel coverage we always need to read the dst in order to correctly
// blend. The one exception is when we are using srcover mode and we know the input color into
// the XP.
if (covPOI.isFourChannelOutput()) {
if (kRGBA_GrColorComponentFlags == colorPOI.validFlags() &&
!caps.shaderCaps()->dstReadInShaderSupport()) {
return false;
}
return get_lcd_blend_formula(covPOI, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
}
// We fallback on the shader XP when the blend formula would use dual source blending but we
// don't have support for it.
return get_blend_formula(colorPOI, covPOI,
hasMixedSamples, SkXfermode::kSrcOver_Mode).hasSecondaryOutput();
}
GR_DEFINE_XP_FACTORY_TEST(GrSrcOverPDXPFactory);
const GrXPFactory* GrSrcOverPDXPFactory::TestCreate(GrProcessorTestData* d) {
return SkRef(&GrPorterDuffXPFactory::gSrcOverPDXPFactory);
}

View File

@ -77,7 +77,7 @@ public:
struct XPInfo {
XPInfo(skiatest::Reporter* reporter, SkXfermode::Mode xfermode, const GrCaps& caps,
const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI) {
SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
SkAutoTUnref<const GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
SkAutoTUnref<GrXferProcessor> xp(
xpf->createXferProcessor(colorPOI, covPOI, false, nullptr, caps));
TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI, false));
@ -97,7 +97,7 @@ public:
};
static void GetXPOutputTypes(const GrXferProcessor* xp, int* outPrimary, int* outSecondary) {
GrPorterDuffXPFactory::TestGetXPOutputTypes(xp, outPrimary, outSecondary);
GrPDXPFactory::TestGetXPOutputTypes(xp, outPrimary, outSecondary);
}
};
@ -1124,7 +1124,7 @@ static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const
SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
SkASSERT(covPOI.isFourChannelOutput());
SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode));
SkAutoTUnref<const GrXPFactory> xpf(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode));
TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI, false));
SkAutoTUnref<GrXferProcessor> xp(
@ -1200,7 +1200,7 @@ static void test_no_dual_source_blending(skiatest::Reporter* reporter) {
}
for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
SkAutoTUnref<const GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
GrXferProcessor::DstTexture* dstTexture =
xpf->willNeedDstTexture(caps, colorPOI, covPOI, false) ? &fakeDstTexture : 0;
SkAutoTUnref<GrXferProcessor> xp(