blob: 36042e19ab21fb1b224406481ee41635ffdecc02 [file] [log] [blame]
/*
* 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;
}
}