/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrDrawState.h" #include "GrBlend.h" #include "GrOptDrawState.h" #include "GrPaint.h" #include "GrProcOptInfo.h" #include "GrXferProcessor.h" #include "effects/GrPorterDuffXferProcessor.h" bool GrDrawState::isEqual(const GrDrawState& that, bool explicitLocalCoords) const { if (this->getRenderTarget() != that.getRenderTarget() || this->fColorStages.count() != that.fColorStages.count() || this->fCoverageStages.count() != that.fCoverageStages.count() || this->fFlagBits != that.fFlagBits || this->fStencilSettings != that.fStencilSettings || this->fDrawFace != that.fDrawFace) { return false; } if (!this->getXPFactory()->isEqual(*that.getXPFactory())) { return false; } for (int i = 0; i < this->numColorStages(); i++) { if (this->getColorStage(i) != that.getColorStage(i)) { return false; } } for (int i = 0; i < this->numCoverageStages(); i++) { if (this->getCoverageStage(i) != that.getCoverageStage(i)) { return false; } } return true; } ////////////////////////////////////////////////////////////////////////////// GrDrawState& GrDrawState::operator=(const GrDrawState& that) { fRenderTarget.reset(SkSafeRef(that.fRenderTarget.get())); fFlagBits = that.fFlagBits; fStencilSettings = that.fStencilSettings; fDrawFace = that.fDrawFace; fXPFactory.reset(SkRef(that.getXPFactory())); fColorStages = that.fColorStages; fCoverageStages = that.fCoverageStages; fColorProcInfoValid = that.fColorProcInfoValid; fCoverageProcInfoValid = that.fCoverageProcInfoValid; fColorCache = that.fColorCache; fCoverageCache = that.fCoverageCache; fColorPrimProc = that.fColorPrimProc; fCoveragePrimProc = that.fCoveragePrimProc; if (fColorProcInfoValid) { fColorProcInfo = that.fColorProcInfo; } if (fCoverageProcInfoValid) { fCoverageProcInfo = that.fCoverageProcInfo; } return *this; } void GrDrawState::onReset() { SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numFragmentStages()); fRenderTarget.reset(NULL); fXPFactory.reset(GrPorterDuffXPFactory::Create(SkXfermode::kSrc_Mode)); fColorStages.reset(); fCoverageStages.reset(); fFlagBits = 0x0; fStencilSettings.setDisabled(); fDrawFace = kBoth_DrawFace; fColorProcInfoValid = false; fCoverageProcInfoValid = false; fColorCache = GrColor_ILLEGAL; fCoverageCache = GrColor_ILLEGAL; fColorPrimProc = NULL; fCoveragePrimProc = NULL; } void GrDrawState::setFromPaint(const GrPaint& paint, GrRenderTarget* rt) { SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numFragmentStages()); fColorStages.reset(); fCoverageStages.reset(); for (int i = 0; i < paint.numColorStages(); ++i) { fColorStages.push_back(paint.getColorStage(i)); } for (int i = 0; i < paint.numCoverageStages(); ++i) { fCoverageStages.push_back(paint.getCoverageStage(i)); } fXPFactory.reset(SkRef(paint.getXPFactory())); this->setRenderTarget(rt); // These have no equivalent in GrPaint, set them to defaults fDrawFace = kBoth_DrawFace; fStencilSettings.setDisabled(); fFlagBits = 0; // Enable the clip bit this->enableState(GrDrawState::kClip_StateBit); this->setState(GrDrawState::kDither_StateBit, paint.isDither()); this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias()); fColorProcInfoValid = false; fCoverageProcInfoValid = false; fColorCache = GrColor_ILLEGAL; fCoverageCache = GrColor_ILLEGAL; fColorPrimProc = NULL; fCoveragePrimProc = NULL; } //////////////////////////////////////////////////////////////////////////////// bool GrDrawState::canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const { if (caps.dualSourceBlendingSupport()) { return true; } this->calcColorInvariantOutput(color); // The coverage isn't actually white, its unknown, but this will produce the same effect // TODO we want to cache the result of this call, but we can probably clean up the interface // so we don't have to pass in a seemingly known coverage this->calcCoverageInvariantOutput(GrColor_WHITE); return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo); } //////////////////////////////////////////////////////////////////////////////s bool GrDrawState::willEffectReadDstColor(const GrPrimitiveProcessor* pp) const { this->calcColorInvariantOutput(pp); this->calcCoverageInvariantOutput(pp); return fXPFactory->willReadDst(fColorProcInfo, fCoverageProcInfo); } void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { if (fDrawState) { int m = fDrawState->numColorStages() - fColorEffectCnt; SkASSERT(m >= 0); fDrawState->fColorStages.pop_back_n(m); int n = fDrawState->numCoverageStages() - fCoverageEffectCnt; SkASSERT(n >= 0); fDrawState->fCoverageStages.pop_back_n(n); if (m + n > 0) { fDrawState->fColorProcInfoValid = false; fDrawState->fCoverageProcInfoValid = false; } SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;) } fDrawState = ds; if (NULL != ds) { fColorEffectCnt = ds->numColorStages(); fCoverageEffectCnt = ds->numCoverageStages(); SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;) } } //////////////////////////////////////////////////////////////////////////////// // Some blend modes allow folding a fractional coverage value into the color's alpha channel, while // others will blend incorrectly. bool GrDrawState::canTweakAlphaForCoverage() const { return fXPFactory->canTweakAlphaForCoverage(); } //////////////////////////////////////////////////////////////////////////////// GrDrawState::~GrDrawState() { SkASSERT(0 == fBlockEffectRemovalCnt); } //////////////////////////////////////////////////////////////////////////////// bool GrDrawState::willBlendWithDst(const GrPrimitiveProcessor* pp) const { this->calcColorInvariantOutput(pp); this->calcCoverageInvariantOutput(pp); GrXPFactory::InvariantOutput output; fXPFactory->getInvariantOutput(fColorProcInfo, fCoverageProcInfo, &output); return output.fWillBlendWithDst; } void GrDrawState::calcColorInvariantOutput(const GrPrimitiveProcessor* pp) const { if (!fColorProcInfoValid || fColorPrimProc != pp) { fColorProcInfo.calcColorWithPrimProc(pp, fColorStages.begin(), this->numColorStages()); fColorProcInfoValid = true; fColorPrimProc = pp; } } void GrDrawState::calcCoverageInvariantOutput(const GrPrimitiveProcessor* pp) const { if (!fCoverageProcInfoValid || fCoveragePrimProc != pp) { fCoverageProcInfo.calcCoverageWithPrimProc(pp, fCoverageStages.begin(), this->numCoverageStages()); fCoverageProcInfoValid = true; fCoveragePrimProc = pp; } } void GrDrawState::calcColorInvariantOutput(GrColor color) const { if (!fColorProcInfoValid || color != fColorCache) { GrColorComponentFlags flags = kRGBA_GrColorComponentFlags; fColorProcInfo.calcWithInitialValues(fColorStages.begin(), this->numColorStages(), color, flags, false); fColorProcInfoValid = true; fColorCache = color; } } void GrDrawState::calcCoverageInvariantOutput(GrColor coverage) const { if (!fCoverageProcInfoValid || coverage != fCoverageCache) { GrColorComponentFlags flags = kRGBA_GrColorComponentFlags; fCoverageProcInfo.calcWithInitialValues(fCoverageStages.begin(), this->numCoverageStages(), coverage, flags, true); fCoverageProcInfoValid = true; fCoverageCache = coverage; } }