*/
#include "GrDrawState.h"
+
+#include "GrOptDrawState.h"
#include "GrPaint.h"
+//////////////////////////////////////////////////////////////////////////////s
+
+bool GrDrawState::isEqual(const GrDrawState& that) const {
+ bool usingVertexColors = this->hasColorVertexAttribute();
+ if (!usingVertexColors && this->fColor != that.fColor) {
+ return false;
+ }
+
+ if (this->getRenderTarget() != that.getRenderTarget() ||
+ this->fColorStages.count() != that.fColorStages.count() ||
+ this->fCoverageStages.count() != that.fCoverageStages.count() ||
+ !this->fViewMatrix.cheapEqualTo(that.fViewMatrix) ||
+ this->fSrcBlend != that.fSrcBlend ||
+ this->fDstBlend != that.fDstBlend ||
+ this->fBlendConstant != that.fBlendConstant ||
+ this->fFlagBits != that.fFlagBits ||
+ this->fVACount != that.fVACount ||
+ this->fVAStride != that.fVAStride ||
+ memcmp(this->fVAPtr, that.fVAPtr, this->fVACount * sizeof(GrVertexAttrib)) ||
+ this->fStencilSettings != that.fStencilSettings ||
+ this->fDrawFace != that.fDrawFace) {
+ return false;
+ }
+
+ bool usingVertexCoverage = this->hasCoverageVertexAttribute();
+ if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
+ return false;
+ }
+
+ bool explicitLocalCoords = this->hasLocalCoordAttribute();
+ if (this->hasGeometryProcessor()) {
+ if (!that.hasGeometryProcessor()) {
+ return false;
+ } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
+ return false;
+ }
+ } else if (that.hasGeometryProcessor()) {
+ return false;
+ }
+
+ for (int i = 0; i < this->numColorStages(); i++) {
+ if (!GrFragmentStage::AreCompatible(this->getColorStage(i), that.getColorStage(i),
+ explicitLocalCoords)) {
+ return false;
+ }
+ }
+ for (int i = 0; i < this->numCoverageStages(); i++) {
+ if (!GrFragmentStage::AreCompatible(this->getCoverageStage(i), that.getCoverageStage(i),
+ explicitLocalCoords)) {
+ return false;
+ }
+ }
+
+ SkASSERT(0 == memcmp(this->fFixedFunctionVertexAttribIndices,
+ that.fFixedFunctionVertexAttribIndices,
+ sizeof(this->fFixedFunctionVertexAttribIndices)));
+
+ return true;
+}
+
+GrDrawState::CombinedState GrDrawState::CombineIfPossible(
+ const GrDrawState& a, const GrDrawState& b, const GrDrawTargetCaps& caps) {
+
+ if (!a.isEqual(b)) {
+ return kIncompatible_CombinedState;
+ }
+
+ // If the general draw states are equal (from check above) we know hasColorVertexAttribute()
+ // is equivalent for both a and b
+ if (a.hasColorVertexAttribute()) {
+ // If one is opaque and the other is not then the combined state is not opaque. Moreover,
+ // if the opaqueness affects the ability to get color/coverage blending correct then we
+ // don't combine the draw states.
+ bool aIsOpaque = (kVertexColorsAreOpaque_Hint & a.fHints);
+ bool bIsOpaque = (kVertexColorsAreOpaque_Hint & b.fHints);
+ if (aIsOpaque != bIsOpaque) {
+ const GrDrawState* opaque;
+ const GrDrawState* nonOpaque;
+ if (aIsOpaque) {
+ opaque = &a;
+ nonOpaque = &b;
+ } else {
+ opaque = &b;
+ nonOpaque = &a;
+ }
+ if (!opaque->hasSolidCoverage() && opaque->couldApplyCoverage(caps)) {
+ SkASSERT(!nonOpaque->hasSolidCoverage());
+ if (!nonOpaque->couldApplyCoverage(caps)) {
+ return kIncompatible_CombinedState;
+ }
+ }
+ return aIsOpaque ? kB_CombinedState : kA_CombinedState;
+ }
+ }
+ return kAOrB_CombinedState;
+}
+
+//////////////////////////////////////////////////////////////////////////////s
+
+GrDrawState::GrDrawState(const GrDrawState& state, const SkMatrix& preConcatMatrix)
+ : fCachedOptState(NULL) {
+ SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
+ *this = state;
+ if (!preConcatMatrix.isIdentity()) {
+ for (int i = 0; i < this->numColorStages(); ++i) {
+ fColorStages[i].localCoordChange(preConcatMatrix);
+ }
+ for (int i = 0; i < this->numCoverageStages(); ++i) {
+ fCoverageStages[i].localCoordChange(preConcatMatrix);
+ }
+ this->invalidateOptState();
+ }
+}
+
+GrDrawState& GrDrawState::operator=(const GrDrawState& that) {
+ SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
+ SkASSERT(!that.fRenderTarget.ownsPendingIO());
+ SkASSERT(!this->fRenderTarget.ownsPendingIO());
+ this->setRenderTarget(that.getRenderTarget());
+ fColor = that.fColor;
+ fViewMatrix = that.fViewMatrix;
+ fSrcBlend = that.fSrcBlend;
+ fDstBlend = that.fDstBlend;
+ fBlendConstant = that.fBlendConstant;
+ fFlagBits = that.fFlagBits;
+ fVACount = that.fVACount;
+ fVAPtr = that.fVAPtr;
+ fVAStride = that.fVAStride;
+ fStencilSettings = that.fStencilSettings;
+ fCoverage = that.fCoverage;
+ fDrawFace = that.fDrawFace;
+ if (that.hasGeometryProcessor()) {
+ fGeometryProcessor.initAndRef(that.fGeometryProcessor);
+ } else {
+ fGeometryProcessor.reset(NULL);
+ }
+ fColorStages = that.fColorStages;
+ fCoverageStages = that.fCoverageStages;
+
+ fHints = that.fHints;
+
+ SkRefCnt_SafeAssign(fCachedOptState, that.fCachedOptState);
+
+ memcpy(fFixedFunctionVertexAttribIndices,
+ that.fFixedFunctionVertexAttribIndices,
+ sizeof(fFixedFunctionVertexAttribIndices));
+ return *this;
+}
+
+void GrDrawState::onReset(const SkMatrix* initialViewMatrix) {
+ SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
+ SkASSERT(!fRenderTarget.ownsPendingIO());
+
+ fGeometryProcessor.reset(NULL);
+ fColorStages.reset();
+ fCoverageStages.reset();
+
+ fRenderTarget.reset();
+
+ this->setDefaultVertexAttribs();
+
+ fColor = 0xffffffff;
+ if (NULL == initialViewMatrix) {
+ fViewMatrix.reset();
+ } else {
+ fViewMatrix = *initialViewMatrix;
+ }
+ fSrcBlend = kOne_GrBlendCoeff;
+ fDstBlend = kZero_GrBlendCoeff;
+ fBlendConstant = 0x0;
+ fFlagBits = 0x0;
+ fStencilSettings.setDisabled();
+ fCoverage = 0xff;
+ fDrawFace = kBoth_DrawFace;
+
+ fHints = 0;
+
+ this->invalidateOptState();
+}
+
bool GrDrawState::setIdentityViewMatrix() {
- if (fColorStages.count() || fCoverageStages.count()) {
+ if (this->numTotalStages()) {
SkMatrix invVM;
- if (!fCommon.fViewMatrix.invert(&invVM)) {
+ if (!fViewMatrix.invert(&invVM)) {
// sad trombone sound
return false;
}
- for (int s = 0; s < fColorStages.count(); ++s) {
+ for (int s = 0; s < this->numColorStages(); ++s) {
fColorStages[s].localCoordChange(invVM);
}
- for (int s = 0; s < fCoverageStages.count(); ++s) {
+ for (int s = 0; s < this->numCoverageStages(); ++s) {
fCoverageStages[s].localCoordChange(invVM);
}
}
- fCommon.fViewMatrix.reset();
+ this->invalidateOptState();
+ fViewMatrix.reset();
return true;
}
void GrDrawState::setFromPaint(const GrPaint& paint, const SkMatrix& vm, GrRenderTarget* rt) {
SkASSERT(0 == fBlockEffectRemovalCnt || 0 == this->numTotalStages());
+ fGeometryProcessor.reset(NULL);
fColorStages.reset();
fCoverageStages.reset();
this->setRenderTarget(rt);
- fCommon.fViewMatrix = vm;
+ fViewMatrix = vm;
// These have no equivalent in GrPaint, set them to defaults
- fCommon.fBlendConstant = 0x0;
- fCommon.fDrawFace = kBoth_DrawFace;
- fCommon.fStencilSettings.setDisabled();
+ fBlendConstant = 0x0;
+ fDrawFace = kBoth_DrawFace;
+ fStencilSettings.setDisabled();
this->resetStateFlags();
+ fHints = 0;
// Enable the clip bit
this->enableState(GrDrawState::kClip_StateBit);
this->setColor(paint.getColor());
- this->setCoverage4(paint.getCoverage());
this->setState(GrDrawState::kDither_StateBit, paint.isDither());
this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
this->setCoverage(paint.getCoverage());
+ this->invalidateOptState();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool GrDrawState::validateVertexAttribs() const {
+ // check consistency of effects and attributes
+ GrSLType slTypes[kMaxVertexAttribCnt];
+ for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
+ slTypes[i] = static_cast<GrSLType>(-1);
+ }
+
+ if (this->hasGeometryProcessor()) {
+ const GrGeometryProcessor* gp = this->getGeometryProcessor();
+ // make sure that any attribute indices have the correct binding type, that the attrib
+ // type and effect's shader lang type are compatible, and that attributes shared by
+ // multiple effects use the same shader lang type.
+ const GrGeometryProcessor::VertexAttribArray& s = gp->getVertexAttribs();
+
+ int effectIndex = 0;
+ for (int index = 0; index < fVACount; index++) {
+ if (kGeometryProcessor_GrVertexAttribBinding != fVAPtr[index].fBinding) {
+ // we only care about effect bindings
+ continue;
+ }
+ SkASSERT(effectIndex < s.count());
+ GrSLType effectSLType = s[effectIndex].getType();
+ GrVertexAttribType attribType = fVAPtr[index].fType;
+ int slVecCount = GrSLTypeVectorCount(effectSLType);
+ int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
+ if (slVecCount != attribVecCount ||
+ (static_cast<GrSLType>(-1) != slTypes[index] && slTypes[index] != effectSLType)) {
+ return false;
+ }
+ slTypes[index] = effectSLType;
+ effectIndex++;
+ }
+ // Make sure all attributes are consumed and we were able to find everything
+ SkASSERT(s.count() == effectIndex);
+ }
+
+ return true;
}
////////////////////////////////////////////////////////////////////////////////
-static size_t vertex_size(const GrVertexAttrib* attribs, int count) {
+static void validate_vertex_attribs(const GrVertexAttrib* attribs, int count, size_t stride) {
// this works as long as we're 4 byte-aligned
#ifdef SK_DEBUG
uint32_t overlapCheck = 0;
-#endif
SkASSERT(count <= GrDrawState::kMaxVertexAttribCnt);
- size_t size = 0;
for (int index = 0; index < count; ++index) {
size_t attribSize = GrVertexAttribTypeSize(attribs[index].fType);
- size += attribSize;
-#ifdef SK_DEBUG
+ size_t attribOffset = attribs[index].fOffset;
+ SkASSERT(attribOffset + attribSize <= stride);
size_t dwordCount = attribSize >> 2;
uint32_t mask = (1 << dwordCount)-1;
- size_t offsetShift = attribs[index].fOffset >> 2;
+ size_t offsetShift = attribOffset >> 2;
SkASSERT(!(overlapCheck & (mask << offsetShift)));
overlapCheck |= (mask << offsetShift);
-#endif
}
- return size;
-}
-
-size_t GrDrawState::getVertexSize() const {
- return vertex_size(fCommon.fVAPtr, fCommon.fVACount);
+#endif
}
////////////////////////////////////////////////////////////////////////////////
-void GrDrawState::setVertexAttribs(const GrVertexAttrib* attribs, int count) {
+void GrDrawState::internalSetVertexAttribs(const GrVertexAttrib* attribs, int count,
+ size_t stride) {
SkASSERT(count <= kMaxVertexAttribCnt);
- fCommon.fVAPtr = attribs;
- fCommon.fVACount = count;
+ fVAPtr = attribs;
+ fVACount = count;
+ fVAStride = stride;
+ validate_vertex_attribs(fVAPtr, fVACount, fVAStride);
// Set all the indices to -1
- memset(fCommon.fFixedFunctionVertexAttribIndices,
+ memset(fFixedFunctionVertexAttribIndices,
0xff,
- sizeof(fCommon.fFixedFunctionVertexAttribIndices));
+ sizeof(fFixedFunctionVertexAttribIndices));
#ifdef SK_DEBUG
uint32_t overlapCheck = 0;
#endif
for (int i = 0; i < count; ++i) {
if (attribs[i].fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
// The fixed function attribs can only be specified once
- SkASSERT(-1 == fCommon.fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
+ SkASSERT(-1 == fFixedFunctionVertexAttribIndices[attribs[i].fBinding]);
SkASSERT(GrFixedFunctionVertexAttribVectorCount(attribs[i].fBinding) ==
GrVertexAttribTypeVectorCount(attribs[i].fType));
- fCommon.fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
+ fFixedFunctionVertexAttribIndices[attribs[i].fBinding] = i;
}
#ifdef SK_DEBUG
size_t dwordCount = GrVertexAttribTypeSize(attribs[i].fType) >> 2;
overlapCheck |= (mask << offsetShift);
#endif
}
+ this->invalidateOptState();
// Positions must be specified.
- SkASSERT(-1 != fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
+ SkASSERT(-1 != fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding]);
}
////////////////////////////////////////////////////////////////////////////////
static const GrVertexAttrib kPositionAttrib =
{kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding};
- fCommon.fVAPtr = &kPositionAttrib;
- fCommon.fVACount = 1;
+ fVAPtr = &kPositionAttrib;
+ fVACount = 1;
+ fVAStride = GrVertexAttribTypeSize(kVec2f_GrVertexAttribType);
// set all the fixed function indices to -1 except position.
- memset(fCommon.fFixedFunctionVertexAttribIndices,
+ memset(fFixedFunctionVertexAttribIndices,
0xff,
- sizeof(fCommon.fFixedFunctionVertexAttribIndices));
- fCommon.fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
+ sizeof(fFixedFunctionVertexAttribIndices));
+ fFixedFunctionVertexAttribIndices[kPosition_GrVertexAttribBinding] = 0;
+ this->invalidateOptState();
}
////////////////////////////////////////////////////////////////////////////////
-bool GrDrawState::validateVertexAttribs() const {
- // check consistency of effects and attributes
- GrSLType slTypes[kMaxVertexAttribCnt];
- for (int i = 0; i < kMaxVertexAttribCnt; ++i) {
- slTypes[i] = static_cast<GrSLType>(-1);
+bool GrDrawState::couldApplyCoverage(const GrDrawTargetCaps& caps) const {
+ if (caps.dualSourceBlendingSupport()) {
+ return true;
}
- int totalStages = fColorStages.count() + fCoverageStages.count();
- for (int s = 0; s < totalStages; ++s) {
- int covIdx = s - fColorStages.count();
- const GrEffectStage& stage = covIdx < 0 ? fColorStages[s] : fCoverageStages[covIdx];
- const GrEffectRef* effect = stage.getEffect();
- SkASSERT(NULL != effect);
- // make sure that any attribute indices have the correct binding type, that the attrib
- // type and effect's shader lang type are compatible, and that attributes shared by
- // multiple effects use the same shader lang type.
- const int* attributeIndices = stage.getVertexAttribIndices();
- int numAttributes = stage.getVertexAttribIndexCount();
- for (int i = 0; i < numAttributes; ++i) {
- int attribIndex = attributeIndices[i];
- if (attribIndex >= fCommon.fVACount ||
- kEffect_GrVertexAttribBinding != fCommon.fVAPtr[attribIndex].fBinding) {
- return false;
- }
+ // we can correctly apply coverage if a) we have dual source blending
+ // or b) one of our blend optimizations applies
+ // or c) the src, dst blend coeffs are 1,0 and we will read Dst Color
+ GrBlendCoeff srcCoeff;
+ GrBlendCoeff dstCoeff;
+ BlendOptFlags flag = this->getBlendOpts(true, &srcCoeff, &dstCoeff);
+ return GrDrawState::kNone_BlendOpt != flag ||
+ (this->willEffectReadDstColor() &&
+ kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff);
+}
- GrSLType effectSLType = (*effect)->vertexAttribType(i);
- GrVertexAttribType attribType = fCommon.fVAPtr[attribIndex].fType;
- int slVecCount = GrSLTypeVectorCount(effectSLType);
- int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
- if (slVecCount != attribVecCount ||
- (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
- slTypes[attribIndex] != effectSLType)) {
- return false;
- }
- slTypes[attribIndex] = effectSLType;
- }
+bool GrDrawState::hasSolidCoverage() const {
+ // If we're drawing coverage directly then coverage is effectively treated as color.
+ if (this->isCoverageDrawing()) {
+ return true;
}
- return true;
+ GrProcessor::InvariantOutput inout;
+ inout.fIsSingleComponent = true;
+ // Initialize to an unknown starting coverage if per-vertex coverage is specified.
+ if (this->hasCoverageVertexAttribute()) {
+ inout.fValidFlags = 0;
+ } else {
+ inout.fColor = this->getCoverageColor();
+ inout.fValidFlags = kRGBA_GrColorComponentFlags;
+ }
+
+ // Run through the coverage stages and see if the coverage will be all ones at the end.
+ if (this->hasGeometryProcessor()) {
+ fGeometryProcessor->computeInvariantOutput(&inout);
+ }
+
+ for (int s = 0; s < this->numCoverageStages(); ++s) {
+ const GrProcessor* processor = this->getCoverageStage(s).getProcessor();
+ processor->computeInvariantOutput(&inout);
+ }
+ return inout.isSolidWhite();
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrDrawState::AutoVertexAttribRestore::AutoVertexAttribRestore(GrDrawState* drawState) {
+ SkASSERT(drawState);
+ fDrawState = drawState;
+ fVAPtr = drawState->fVAPtr;
+ fVACount = drawState->fVACount;
+ fVAStride = drawState->fVAStride;
+ fDrawState->setDefaultVertexAttribs();
}
+//////////////////////////////////////////////////////////////////////////////s
+
bool GrDrawState::willEffectReadDstColor() const {
if (!this->isColorWriteDisabled()) {
- for (int s = 0; s < fColorStages.count(); ++s) {
- if ((*fColorStages[s].getEffect())->willReadDstColor()) {
+ for (int s = 0; s < this->numColorStages(); ++s) {
+ if (this->getColorStage(s).getProcessor()->willReadDstColor()) {
return true;
}
}
}
- for (int s = 0; s < fCoverageStages.count(); ++s) {
- if ((*fCoverageStages[s].getEffect())->willReadDstColor()) {
+ for (int s = 0; s < this->numCoverageStages(); ++s) {
+ if (this->getCoverageStage(s).getProcessor()->willReadDstColor()) {
return true;
}
}
return false;
}
-////////////////////////////////////////////////////////////////////////////////
-
-bool GrDrawState::srcAlphaWillBeOne() const {
- uint32_t validComponentFlags;
- GrColor color;
- // Check if per-vertex or constant color may have partial alpha
- if (this->hasColorVertexAttribute()) {
- validComponentFlags = 0;
- color = 0; // not strictly necessary but we get false alarms from tools about uninit.
- } else {
- validComponentFlags = kRGBA_GrColorComponentFlags;
- color = this->getColor();
- }
-
- // Run through the color stages
- for (int s = 0; s < fColorStages.count(); ++s) {
- const GrEffectRef* effect = fColorStages[s].getEffect();
- (*effect)->getConstantColorComponents(&color, &validComponentFlags);
- }
-
- // Check whether coverage is treated as color. If so we run through the coverage computation.
- if (this->isCoverageDrawing()) {
- GrColor coverageColor = this->getCoverage();
- GrColor oldColor = color;
- color = 0;
- for (int c = 0; c < 4; ++c) {
- if (validComponentFlags & (1 << c)) {
- U8CPU a = (oldColor >> (c * 8)) & 0xff;
- U8CPU b = (coverageColor >> (c * 8)) & 0xff;
- color |= (SkMulDiv255Round(a, b) << (c * 8));
- }
- }
- for (int s = 0; s < fCoverageStages.count(); ++s) {
- const GrEffectRef* effect = fCoverageStages[s].getEffect();
- (*effect)->getConstantColorComponents(&color, &validComponentFlags);
+void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) {
+ if (fDrawState) {
+ // See the big comment on the class definition about GPs.
+ if (SK_InvalidUniqueID == fOriginalGPID) {
+ fDrawState->fGeometryProcessor.reset(NULL);
+ } else {
+ SkASSERT(fDrawState->getGeometryProcessor()->getUniqueID() ==
+ fOriginalGPID);
+ fOriginalGPID = SK_InvalidUniqueID;
}
- }
- return (kA_GrColorComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
-}
-bool GrDrawState::hasSolidCoverage() const {
- // If we're drawing coverage directly then coverage is effectively treated as color.
- if (this->isCoverageDrawing()) {
- return true;
- }
+ int m = fDrawState->numColorStages() - fColorEffectCnt;
+ SkASSERT(m >= 0);
+ fDrawState->fColorStages.pop_back_n(m);
- GrColor coverage;
- uint32_t validComponentFlags;
- // Initialize to an unknown starting coverage if per-vertex coverage is specified.
- if (this->hasCoverageVertexAttribute()) {
- validComponentFlags = 0;
- } else {
- coverage = fCommon.fCoverage;
- validComponentFlags = kRGBA_GrColorComponentFlags;
+ int n = fDrawState->numCoverageStages() - fCoverageEffectCnt;
+ SkASSERT(n >= 0);
+ fDrawState->fCoverageStages.pop_back_n(n);
+ if (m + n > 0) {
+ fDrawState->invalidateOptState();
+ }
+ SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
}
-
- // Run through the coverage stages and see if the coverage will be all ones at the end.
- for (int s = 0; s < fCoverageStages.count(); ++s) {
- const GrEffectRef* effect = fCoverageStages[s].getEffect();
- (*effect)->getConstantColorComponents(&coverage, &validComponentFlags);
+ fDrawState = ds;
+ if (NULL != ds) {
+ SkASSERT(SK_InvalidUniqueID == fOriginalGPID);
+ if (NULL != ds->getGeometryProcessor()) {
+ fOriginalGPID = ds->getGeometryProcessor()->getUniqueID();
+ }
+ fColorEffectCnt = ds->numColorStages();
+ fCoverageEffectCnt = ds->numCoverageStages();
+ SkDEBUGCODE(++ds->fBlockEffectRemovalCnt;)
}
- return (kRGBA_GrColorComponentFlags == validComponentFlags) && (0xffffffff == coverage);
}
////////////////////////////////////////////////////////////////////////////////
Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
color by definition.
*/
- return kOne_GrBlendCoeff == fCommon.fDstBlend ||
- kISA_GrBlendCoeff == fCommon.fDstBlend ||
- kISC_GrBlendCoeff == fCommon.fDstBlend ||
+ return kOne_GrBlendCoeff == fDstBlend ||
+ kISA_GrBlendCoeff == fDstBlend ||
+ kISC_GrBlendCoeff == fDstBlend ||
this->isCoverageDrawing();
}
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawState::AutoViewMatrixRestore::restore() {
+ if (fDrawState) {
+ SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
+ fDrawState->fViewMatrix = fViewMatrix;
+ SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
+ int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
+ SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
+
+ int i = 0;
+ for (int s = 0; s < fNumColorStages; ++s, ++i) {
+ fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
+ }
+ for (int s = 0; s < numCoverageStages; ++s, ++i) {
+ fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
+ }
+ fDrawState->invalidateOptState();
+ fDrawState = NULL;
+ }
+}
+
+void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
+ const SkMatrix& preconcatMatrix) {
+ this->restore();
+
+ SkASSERT(NULL == fDrawState);
+ if (NULL == drawState || preconcatMatrix.isIdentity()) {
+ return;
+ }
+ fDrawState = drawState;
+
+ fViewMatrix = drawState->getViewMatrix();
+ drawState->fViewMatrix.preConcat(preconcatMatrix);
+
+ this->doEffectCoordChanges(preconcatMatrix);
+ SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
+ drawState->invalidateOptState();
+}
+
+bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
+ this->restore();
+
+ if (NULL == drawState) {
+ return false;
+ }
+
+ if (drawState->getViewMatrix().isIdentity()) {
+ return true;
+ }
+
+ drawState->invalidateOptState();
+ fViewMatrix = drawState->getViewMatrix();
+ if (0 == drawState->numTotalStages()) {
+ drawState->fViewMatrix.reset();
+ fDrawState = drawState;
+ fNumColorStages = 0;
+ fSavedCoordChanges.reset(0);
+ SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
+ return true;
+ } else {
+ SkMatrix inv;
+ if (!fViewMatrix.invert(&inv)) {
+ return false;
+ }
+ drawState->fViewMatrix.reset();
+ fDrawState = drawState;
+ this->doEffectCoordChanges(inv);
+ SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
+ return true;
+ }
+}
+
+void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
+ fSavedCoordChanges.reset(fDrawState->numTotalStages());
+ int i = 0;
+
+ fNumColorStages = fDrawState->numColorStages();
+ for (int s = 0; s < fNumColorStages; ++s, ++i) {
+ fDrawState->getColorStage(s).saveCoordChange(&fSavedCoordChanges[i]);
+ fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
+ }
+
+ int numCoverageStages = fDrawState->numCoverageStages();
+ for (int s = 0; s < numCoverageStages; ++s, ++i) {
+ fDrawState->getCoverageStage(s).saveCoordChange(&fSavedCoordChanges[i]);
+ fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawState::convertToPendingExec() {
+ fRenderTarget.markPendingIO();
+ fRenderTarget.removeRef();
+ for (int i = 0; i < fColorStages.count(); ++i) {
+ fColorStages[i].convertToPendingExec();
+ }
+ if (fGeometryProcessor) {
+ fGeometryProcessor.convertToPendingExec();
+ }
+ for (int i = 0; i < fCoverageStages.count(); ++i) {
+ fCoverageStages[i].convertToPendingExec();
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrDrawState::invalidateOptState() const {
+ SkSafeSetNull(fCachedOptState);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrDrawState::~GrDrawState() {
+ SkSafeUnref(fCachedOptState);
+ SkASSERT(0 == fBlockEffectRemovalCnt);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
GrDrawState::BlendOptFlags GrDrawState::getBlendOpts(bool forceCoverage,
GrBlendCoeff* srcCoeff,
GrBlendCoeff* dstCoeff) const {
-
GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
if (NULL == srcCoeff) {
srcCoeff = &bogusSrcCoeff;
}
- *srcCoeff = this->getSrcBlendCoeff();
-
if (NULL == dstCoeff) {
dstCoeff = &bogusDstCoeff;
}
+
+ *srcCoeff = this->getSrcBlendCoeff();
*dstCoeff = this->getDstBlendCoeff();
if (this->isColorWriteDisabled()) {
bool dstCoeffIsZero = kZero_GrBlendCoeff == *dstCoeff ||
(kISA_GrBlendCoeff == *dstCoeff && srcAIsOne);
- bool covIsZero = !this->isCoverageDrawing() &&
- !this->hasCoverageVertexAttribute() &&
- 0 == this->getCoverage();
// When coeffs are (0,1) there is no reason to draw at all, unless
// stenciling is enabled. Having color writes disabled is effectively
- // (0,1). The same applies when coverage is known to be 0.
- if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne) || covIsZero) {
+ // (0,1).
+ if ((kZero_GrBlendCoeff == *srcCoeff && dstCoeffIsOne)) {
if (this->getStencil().doesWrite()) {
- return kDisableBlend_BlendOptFlag |
- kEmitCoverage_BlendOptFlag;
+ return kEmitCoverage_BlendOptFlag;
} else {
+ *dstCoeff = kOne_GrBlendCoeff;
return kSkipDraw_BlendOptFlag;
}
}
- // check for coverage due to constant coverage, per-vertex coverage, or coverage stage
- bool hasCoverage = forceCoverage ||
- 0xffffffff != this->getCoverage() ||
- this->hasCoverageVertexAttribute() ||
- fCoverageStages.count() > 0;
+ bool hasCoverage = forceCoverage || !this->hasSolidCoverage();
// if we don't have coverage we can check whether the dst
// has to read at all. If not, we'll disable blending.
if (kOne_GrBlendCoeff == *srcCoeff) {
// if there is no coverage and coeffs are (1,0) then we
// won't need to read the dst at all, it gets replaced by src
- return kDisableBlend_BlendOptFlag;
+ *dstCoeff = kZero_GrBlendCoeff;
+ return kNone_BlendOpt;
} else if (kZero_GrBlendCoeff == *srcCoeff) {
// if the op is "clear" then we don't need to emit a color
// or blend, just write transparent black into the dst.
*srcCoeff = kOne_GrBlendCoeff;
*dstCoeff = kZero_GrBlendCoeff;
- return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag;
+ return kEmitTransBlack_BlendOptFlag;
}
}
} else if (this->isCoverageDrawing()) {
return kCoverageAsAlpha_BlendOptFlag;
}
}
- if (kOne_GrBlendCoeff == *srcCoeff &&
- kZero_GrBlendCoeff == *dstCoeff &&
- this->willEffectReadDstColor()) {
- // In this case the shader will fully resolve the color, coverage, and dst and we don't
- // need blending.
- return kDisableBlend_BlendOptFlag;
- }
+
return kNone_BlendOpt;
}
-////////////////////////////////////////////////////////////////////////////////
-
-void GrDrawState::AutoViewMatrixRestore::restore() {
- if (NULL != fDrawState) {
- SkDEBUGCODE(--fDrawState->fBlockEffectRemovalCnt;)
- fDrawState->fCommon.fViewMatrix = fViewMatrix;
- SkASSERT(fDrawState->numColorStages() >= fNumColorStages);
- int numCoverageStages = fSavedCoordChanges.count() - fNumColorStages;
- SkASSERT(fDrawState->numCoverageStages() >= numCoverageStages);
- int i = 0;
- for (int s = 0; s < fNumColorStages; ++s, ++i) {
- fDrawState->fColorStages[s].restoreCoordChange(fSavedCoordChanges[i]);
- }
- for (int s = 0; s < numCoverageStages; ++s, ++i) {
- fDrawState->fCoverageStages[s].restoreCoordChange(fSavedCoordChanges[i]);
+bool GrDrawState::srcAlphaWillBeOne() const {
+ GrProcessor::InvariantOutput inoutColor;
+ inoutColor.fIsSingleComponent = false;
+ // Check if per-vertex or constant color may have partial alpha
+ if (this->hasColorVertexAttribute()) {
+ if (fHints & kVertexColorsAreOpaque_Hint) {
+ inoutColor.fValidFlags = kA_GrColorComponentFlag;
+ inoutColor.fColor = 0xFF << GrColor_SHIFT_A;
+ } else {
+ inoutColor.fValidFlags = 0;
+ // not strictly necessary but we get false alarms from tools about uninit.
+ inoutColor.fColor = 0;
}
- fDrawState = NULL;
- }
-}
-
-void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
- const SkMatrix& preconcatMatrix) {
- this->restore();
-
- SkASSERT(NULL == fDrawState);
- if (NULL == drawState || preconcatMatrix.isIdentity()) {
- return;
+ } else {
+ inoutColor.fValidFlags = kRGBA_GrColorComponentFlags;
+ inoutColor.fColor = this->getColor();
}
- fDrawState = drawState;
-
- fViewMatrix = drawState->getViewMatrix();
- drawState->fCommon.fViewMatrix.preConcat(preconcatMatrix);
-
- this->doEffectCoordChanges(preconcatMatrix);
- SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
-}
-
-bool GrDrawState::AutoViewMatrixRestore::setIdentity(GrDrawState* drawState) {
- this->restore();
- if (NULL == drawState) {
- return false;
+ // Run through the color stages
+ for (int s = 0; s < this->numColorStages(); ++s) {
+ const GrProcessor* processor = this->getColorStage(s).getProcessor();
+ processor->computeInvariantOutput(&inoutColor);
}
- if (drawState->getViewMatrix().isIdentity()) {
- return true;
- }
+ // Check whether coverage is treated as color. If so we run through the coverage computation.
+ if (this->isCoverageDrawing()) {
+ // The shader generated for coverage drawing runs the full coverage computation and then
+ // makes the shader output be the multiplication of color and coverage. We mirror that here.
+ GrProcessor::InvariantOutput inoutCoverage;
+ inoutCoverage.fIsSingleComponent = true;
+ if (this->hasCoverageVertexAttribute()) {
+ inoutCoverage.fValidFlags = 0;
+ inoutCoverage.fColor = 0; // suppresses any warnings.
+ } else {
+ inoutCoverage.fValidFlags = kRGBA_GrColorComponentFlags;
+ inoutCoverage.fColor = this->getCoverageColor();
+ }
- fViewMatrix = drawState->getViewMatrix();
- if (0 == drawState->numTotalStages()) {
- drawState->fCommon.fViewMatrix.reset();
- fDrawState = drawState;
- fNumColorStages = 0;
- fSavedCoordChanges.reset(0);
- SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
- return true;
- } else {
- SkMatrix inv;
- if (!fViewMatrix.invert(&inv)) {
- return false;
+ if (this->hasGeometryProcessor()) {
+ fGeometryProcessor->computeInvariantOutput(&inoutCoverage);
}
- drawState->fCommon.fViewMatrix.reset();
- fDrawState = drawState;
- this->doEffectCoordChanges(inv);
- SkDEBUGCODE(++fDrawState->fBlockEffectRemovalCnt;)
- return true;
- }
-}
-void GrDrawState::AutoViewMatrixRestore::doEffectCoordChanges(const SkMatrix& coordChangeMatrix) {
- fSavedCoordChanges.reset(fDrawState->numTotalStages());
- int i = 0;
+ // Run through the coverage stages
+ for (int s = 0; s < this->numCoverageStages(); ++s) {
+ const GrProcessor* processor = this->getCoverageStage(s).getProcessor();
+ processor->computeInvariantOutput(&inoutCoverage);
+ }
- fNumColorStages = fDrawState->numColorStages();
- for (int s = 0; s < fNumColorStages; ++s, ++i) {
- fDrawState->fColorStages[s].saveCoordChange(&fSavedCoordChanges[i]);
- fDrawState->fColorStages[s].localCoordChange(coordChangeMatrix);
+ // Since the shader will multiply coverage and color, the only way the final A==1 is if
+ // coverage and color both have A==1.
+ return (inoutColor.isOpaque() && inoutCoverage.isOpaque());
}
- int numCoverageStages = fDrawState->numCoverageStages();
- for (int s = 0; s < numCoverageStages; ++s, ++i) {
- fDrawState->fCoverageStages[s].saveCoordChange(&fSavedCoordChanges[i]);
- fDrawState->fCoverageStages[s].localCoordChange(coordChangeMatrix);
- }
+ return inoutColor.isOpaque();
}
+