#include "GrDrawState.h"
#include "GrDrawTargetCaps.h"
-#include "GrGpu.h"
+#include "gl/GrGpuGL.h"
GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
BlendOptFlags blendOptFlags,
GrBlendCoeff optSrcCoeff,
GrBlendCoeff optDstCoeff,
- const GrDrawTargetCaps& caps) : INHERITED(drawState) {
+ GrGpu* gpu,
+ const GrDeviceCoordTexture* dstCopy,
+ GrGpu::DrawType drawType) {
+ fRenderTarget.set(SkSafeRef(drawState.getRenderTarget()), kWrite_GrIOType);
fColor = drawState.getColor();
fCoverage = drawState.getCoverage();
fViewMatrix = drawState.getViewMatrix();
fVACount = drawState.getVertexAttribCount();
fVAStride = drawState.getVertexStride();
fStencilSettings = drawState.getStencil();
- fDrawFace = drawState.getDrawFace();
+ fDrawFace = (DrawFace)drawState.getDrawFace();
fBlendOptFlags = blendOptFlags;
fSrcBlend = optSrcCoeff;
fDstBlend = optDstCoeff;
+ GrProgramDesc::DescInfo descInfo;
- memcpy(fFixedFunctionVertexAttribIndices,
- drawState.getFixedFunctionVertexAttribIndices(),
- sizeof(fFixedFunctionVertexAttribIndices));
+ memcpy(descInfo.fFixedFunctionVertexAttribIndices,
+ drawState.getFixedFunctionVertexAttribIndices(),
+ sizeof(descInfo.fFixedFunctionVertexAttribIndices));
+ descInfo.fInputColorIsUsed = true;
+ descInfo.fInputCoverageIsUsed = true;
- fInputColorIsUsed = true;
- fInputCoverageIsUsed = true;
+ int firstColorStageIdx = 0;
+ int firstCoverageStageIdx = 0;
+ bool separateCoverageFromColor;
+ uint8_t fixedFunctionVAToRemove = 0;
+
+ this->computeEffectiveColorStages(drawState, &descInfo, &firstColorStageIdx,
+ &fixedFunctionVAToRemove);
+ this->computeEffectiveCoverageStages(drawState, &descInfo, &firstCoverageStageIdx);
+ this->adjustFromBlendOpts(drawState, &descInfo, &firstColorStageIdx, &firstCoverageStageIdx,
+ &fixedFunctionVAToRemove);
+ // Should not be setting any more FFVA to be removed at this point
+ if (0 != fixedFunctionVAToRemove) {
+ this->removeFixedFunctionVertexAttribs(fixedFunctionVAToRemove, &descInfo);
+ }
+ this->getStageStats(drawState, firstColorStageIdx, firstCoverageStageIdx, &descInfo);
+ this->setOutputStateInfo(drawState, *gpu->caps(), firstCoverageStageIdx, &descInfo,
+ &separateCoverageFromColor);
+
+ // Copy GeometryProcesssor from DS or ODS
if (drawState.hasGeometryProcessor()) {
- fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor())));
+ fGeometryProcessor.initAndRef(drawState.fGeometryProcessor);
} else {
fGeometryProcessor.reset(NULL);
}
- this->copyEffectiveColorStages(drawState);
- this->copyEffectiveCoverageStages(drawState);
- this->adjustFromBlendOpts();
- this->getStageStats();
- this->setOutputStateInfo(caps);
+ // Copy Color Stages from DS to ODS
+ if (firstColorStageIdx < drawState.numColorStages()) {
+ fFragmentStages.reset(&drawState.getColorStage(firstColorStageIdx),
+ drawState.numColorStages() - firstColorStageIdx);
+ } else {
+ fFragmentStages.reset();
+ }
+
+ fNumColorStages = fFragmentStages.count();
+
+ // Copy Coverage Stages from DS to ODS
+ if (firstCoverageStageIdx < drawState.numCoverageStages()) {
+ fFragmentStages.push_back_n(drawState.numCoverageStages() - firstCoverageStageIdx,
+ &drawState.getCoverageStage(firstCoverageStageIdx));
+ if (!separateCoverageFromColor) {
+ fNumColorStages = fFragmentStages.count();
+ }
+ }
+
+ // now create a key
+ gpu->buildProgramDesc(*this, descInfo, drawType, dstCopy, &fDesc);
};
-void GrOptDrawState::setOutputStateInfo(const GrDrawTargetCaps& caps) {
+GrOptDrawState* GrOptDrawState::Create(const GrDrawState& drawState,
+ GrGpu* gpu,
+ const GrDeviceCoordTexture* dstCopy,
+ GrGpu::DrawType drawType) {
+ const GrDrawTargetCaps& caps = *gpu->caps();
+ if (NULL == drawState.fCachedOptState || caps.getUniqueID() != drawState.fCachedCapsID) {
+ GrBlendCoeff srcCoeff;
+ GrBlendCoeff dstCoeff;
+ BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
+ &srcCoeff,
+ &dstCoeff);
+
+ // If our blend coeffs are set to 0,1 we know we will not end up drawing unless we are
+ // stenciling. When path rendering the stencil settings are not always set on the draw state
+ // so we must check the draw type. In cases where we will skip drawing we simply return a
+ // null GrOptDrawState.
+ if (kZero_GrBlendCoeff == srcCoeff && kOne_GrBlendCoeff == dstCoeff &&
+ !drawState.getStencil().doesWrite() && GrGpu::kStencilPath_DrawType != drawType) {
+ return NULL;
+ }
+
+ drawState.fCachedOptState = SkNEW_ARGS(GrOptDrawState, (drawState, blendFlags, srcCoeff,
+ dstCoeff, gpu, dstCopy, drawType));
+ drawState.fCachedCapsID = caps.getUniqueID();
+ } else {
+#ifdef SK_DEBUG
+ GrBlendCoeff srcCoeff;
+ GrBlendCoeff dstCoeff;
+ BlendOptFlags blendFlags = (BlendOptFlags) drawState.getBlendOpts(false,
+ &srcCoeff,
+ &dstCoeff);
+ SkASSERT(GrOptDrawState(drawState, blendFlags, srcCoeff, dstCoeff, gpu, dstCopy,
+ drawType) == *drawState.fCachedOptState);
+#endif
+ }
+ drawState.fCachedOptState->ref();
+ return drawState.fCachedOptState;
+}
+
+void GrOptDrawState::setOutputStateInfo(const GrDrawState& ds,
+ const GrDrawTargetCaps& caps,
+ int firstCoverageStageIdx,
+ GrProgramDesc::DescInfo* descInfo,
+ bool* separateCoverageFromColor) {
// Set this default and then possibly change our mind if there is coverage.
- fPrimaryOutputType = kModulate_PrimaryOutputType;
- fSecondaryOutputType = kNone_SecondaryOutputType;
+ descInfo->fPrimaryOutputType = GrProgramDesc::kModulate_PrimaryOutputType;
+ descInfo->fSecondaryOutputType = GrProgramDesc::kNone_SecondaryOutputType;
// If we do have coverage determine whether it matters.
- bool separateCoverageFromColor = this->hasGeometryProcessor();
+ *separateCoverageFromColor = this->hasGeometryProcessor();
if (!this->isCoverageDrawing() &&
- (this->numCoverageStages() > 0 ||
- this->hasGeometryProcessor() ||
- this->hasCoverageVertexAttribute())) {
+ (ds.numCoverageStages() - firstCoverageStageIdx > 0 ||
+ ds.hasGeometryProcessor() ||
+ descInfo->hasCoverageVertexAttribute())) {
if (caps.dualSourceBlendingSupport()) {
if (kZero_GrBlendCoeff == fDstBlend) {
// write the coverage value to second color
- fSecondaryOutputType = kCoverage_SecondaryOutputType;
- separateCoverageFromColor = true;
+ descInfo->fSecondaryOutputType = GrProgramDesc::kCoverage_SecondaryOutputType;
+ *separateCoverageFromColor = true;
fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
} else if (kSA_GrBlendCoeff == fDstBlend) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
- fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
- separateCoverageFromColor = true;
+ descInfo->fSecondaryOutputType = GrProgramDesc::kCoverageISA_SecondaryOutputType;
+ *separateCoverageFromColor = true;
fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
} else if (kSC_GrBlendCoeff == fDstBlend) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
- fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
- separateCoverageFromColor = true;
+ descInfo->fSecondaryOutputType = GrProgramDesc::kCoverageISC_SecondaryOutputType;
+ *separateCoverageFromColor = true;
fDstBlend = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
}
- } else if (fReadsDst &&
+ } else if (descInfo->fReadsDst &&
kOne_GrBlendCoeff == fSrcBlend &&
kZero_GrBlendCoeff == fDstBlend) {
- fPrimaryOutputType = kCombineWithDst_PrimaryOutputType;
- separateCoverageFromColor = true;
+ descInfo->fPrimaryOutputType = GrProgramDesc::kCombineWithDst_PrimaryOutputType;
+ *separateCoverageFromColor = true;
}
}
-
- // TODO: Once we have flag to know if we only multiply on stages, only push coverage into color
- // stages if everything is multipy
- if (!separateCoverageFromColor) {
- for (int s = 0; s < this->numCoverageStages(); ++s) {
- fColorStages.push_back(this->getCoverageStage(s));
- }
- fCoverageStages.reset();
- }
}
-void GrOptDrawState::adjustFromBlendOpts() {
-
+void GrOptDrawState::adjustFromBlendOpts(const GrDrawState& ds,
+ GrProgramDesc::DescInfo* descInfo,
+ int* firstColorStageIdx,
+ int* firstCoverageStageIdx,
+ uint8_t* fixedFunctionVAToRemove) {
switch (fBlendOptFlags) {
case kNone_BlendOpt:
case kSkipDraw_BlendOptFlag:
break;
case kEmitCoverage_BlendOptFlag:
fColor = 0xffffffff;
- fInputColorIsUsed = true;
- fColorStages.reset();
- this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
+ descInfo->fInputColorIsUsed = true;
+ *firstColorStageIdx = ds.numColorStages();
+ *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
break;
case kEmitTransBlack_BlendOptFlag:
fColor = 0;
fCoverage = 0xff;
- fInputColorIsUsed = true;
- fInputCoverageIsUsed = true;
- fColorStages.reset();
- fCoverageStages.reset();
- this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding |
- 0x1 << kCoverage_GrVertexAttribBinding);
+ descInfo->fInputColorIsUsed = true;
+ descInfo->fInputCoverageIsUsed = true;
+ *firstColorStageIdx = ds.numColorStages();
+ *firstCoverageStageIdx = ds.numCoverageStages();
+ *fixedFunctionVAToRemove |= (0x1 << kColor_GrVertexAttribBinding |
+ 0x1 << kCoverage_GrVertexAttribBinding);
break;
default:
SkFAIL("Unknown BlendOptFlag");
-
}
}
-void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag) {
+void GrOptDrawState::removeFixedFunctionVertexAttribs(uint8_t removeVAFlag,
+ GrProgramDesc::DescInfo* descInfo) {
int numToRemove = 0;
uint8_t maskCheck = 0x1;
// Count the number of vertex attributes that we will actually remove
for (int i = 0; i < kGrFixedFunctionVertexAttribBindingCnt; ++i) {
- if ((maskCheck & removeVAFlag) && -1 != fFixedFunctionVertexAttribIndices[i]) {
+ if ((maskCheck & removeVAFlag) && -1 != descInfo->fFixedFunctionVertexAttribIndices[i]) {
++numToRemove;
}
maskCheck <<= 1;
if (currAttrib.fBinding < kGrFixedFunctionVertexAttribBindingCnt) {
uint8_t maskCheck = 0x1 << currAttrib.fBinding;
if (maskCheck & removeVAFlag) {
- SkASSERT(-1 != fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
- fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
+ SkASSERT(-1 != descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding]);
+ descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = -1;
continue;
}
- fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
+ descInfo->fFixedFunctionVertexAttribIndices[currAttrib.fBinding] = newIdx;
}
memcpy(dst, src, sizeof(GrVertexAttrib));
++newIdx;
fVAPtr = fOptVA.get();
}
-void GrOptDrawState::copyEffectiveColorStages(const GrDrawState& ds) {
- int firstColorStage = 0;
-
+void GrOptDrawState::computeEffectiveColorStages(const GrDrawState& ds,
+ GrProgramDesc::DescInfo* descInfo,
+ int* firstColorStageIdx,
+ uint8_t* fixedFunctionVAToRemove) {
// Set up color and flags for ConstantColorComponent checks
- GrColor color;
- uint32_t validComponentFlags;
- if (!this->hasColorVertexAttribute()) {
- color = ds.getColor();
- validComponentFlags = kRGBA_GrColorComponentFlags;
+ GrProcessor::InvariantOutput inout;
+ inout.fIsSingleComponent = false;
+ if (!descInfo->hasColorVertexAttribute()) {
+ inout.fColor = ds.getColor();
+ inout.fValidFlags = kRGBA_GrColorComponentFlags;
} else {
if (ds.vertexColorsAreOpaque()) {
- color = 0xFF << GrColor_SHIFT_A;
- validComponentFlags = kA_GrColorComponentFlag;
+ inout.fColor = 0xFF << GrColor_SHIFT_A;
+ inout.fValidFlags = kA_GrColorComponentFlag;
} else {
- validComponentFlags = 0;
- color = 0; // not strictly necessary but we get false alarms from tools about uninit.
+ inout.fValidFlags = 0;
+ // not strictly necessary but we get false alarms from tools about uninit.
+ inout.fColor = 0;
}
}
for (int i = 0; i < ds.numColorStages(); ++i) {
- const GrFragmentProcessor* fp = ds.getColorStage(i).getFragmentProcessor();
- if (!fp->willUseInputColor()) {
- firstColorStage = i;
- fInputColorIsUsed = false;
+ const GrFragmentProcessor* fp = ds.getColorStage(i).getProcessor();
+ fp->computeInvariantOutput(&inout);
+ if (!inout.fWillUseInputColor) {
+ *firstColorStageIdx = i;
+ descInfo->fInputColorIsUsed = false;
}
- fp->getConstantColorComponents(&color, &validComponentFlags);
- if (kRGBA_GrColorComponentFlags == validComponentFlags) {
- firstColorStage = i + 1;
- fColor = color;
- fInputColorIsUsed = true;
- this->removeFixedFunctionVertexAttribs(0x1 << kColor_GrVertexAttribBinding);
+ if (kRGBA_GrColorComponentFlags == inout.fValidFlags) {
+ *firstColorStageIdx = i + 1;
+ fColor = inout.fColor;
+ descInfo->fInputColorIsUsed = true;
+ *fixedFunctionVAToRemove |= 0x1 << kColor_GrVertexAttribBinding;
+ // Since we are clearing all previous color stages we are in a state where we have found
+ // zero stages that don't multiply the inputColor.
+ inout.fNonMulStageFound = false;
}
}
- if (firstColorStage < ds.numColorStages()) {
- fColorStages.reset(&ds.getColorStage(firstColorStage),
- ds.numColorStages() - firstColorStage);
- } else {
- fColorStages.reset();
- }
}
-void GrOptDrawState::copyEffectiveCoverageStages(const GrDrawState& ds) {
- int firstCoverageStage = 0;
-
+void GrOptDrawState::computeEffectiveCoverageStages(const GrDrawState& ds,
+ GrProgramDesc::DescInfo* descInfo,
+ int* firstCoverageStageIdx) {
// We do not try to optimize out constantColor coverage effects here. It is extremely rare
// to have a coverage effect that returns a constant value for all four channels. Thus we
// save having to make extra virtual calls by not checking for it.
// Don't do any optimizations on coverage stages. It should not be the case where we do not use
// input coverage in an effect
#ifdef OptCoverageStages
+ GrProcessor::InvariantOutput inout;
for (int i = 0; i < ds.numCoverageStages(); ++i) {
- const GrProcessor* processor = ds.getCoverageStage(i).getProcessor();
- if (!processor->willUseInputColor()) {
- firstCoverageStage = i;
- fInputCoverageIsUsed = false;
+ const GrFragmentProcessor* fp = ds.getCoverageStage(i).getProcessor();
+ fp->computeInvariantOutput(&inout);
+ if (!inout.fWillUseInputColor) {
+ *firstCoverageStageIdx = i;
+ descInfo->fInputCoverageIsUsed = false;
}
}
#endif
- if (ds.numCoverageStages() > 0) {
- fCoverageStages.reset(&ds.getCoverageStage(firstCoverageStage),
- ds.numCoverageStages() - firstCoverageStage);
- } else {
- fCoverageStages.reset();
- }
}
static void get_stage_stats(const GrFragmentStage& stage, bool* readsDst, bool* readsFragPosition) {
- if (stage.getFragmentProcessor()->willReadDstColor()) {
+ if (stage.getProcessor()->willReadDstColor()) {
*readsDst = true;
}
- if (stage.getFragmentProcessor()->willReadFragmentPosition()) {
+ if (stage.getProcessor()->willReadFragmentPosition()) {
*readsFragPosition = true;
}
}
-void GrOptDrawState::getStageStats() {
+void GrOptDrawState::getStageStats(const GrDrawState& ds, int firstColorStageIdx,
+ int firstCoverageStageIdx, GrProgramDesc::DescInfo* descInfo) {
// We will need a local coord attrib if there is one currently set on the optState and we are
// actually generating some effect code
- fRequiresLocalCoordAttrib = this->hasLocalCoordAttribute() && this->numTotalStages() > 0;
+ descInfo->fRequiresLocalCoordAttrib = descInfo->hasLocalCoordAttribute() &&
+ ds.numTotalStages() - firstColorStageIdx - firstCoverageStageIdx > 0;
- fReadsDst = false;
- fReadsFragPosition = false;
+ descInfo->fReadsDst = false;
+ descInfo->fReadsFragPosition = false;
- for (int s = 0; s < this->numColorStages(); ++s) {
- const GrFragmentStage& stage = this->getColorStage(s);
- get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
+ for (int s = firstColorStageIdx; s < ds.numColorStages(); ++s) {
+ const GrFragmentStage& stage = ds.getColorStage(s);
+ get_stage_stats(stage, &descInfo->fReadsDst, &descInfo->fReadsFragPosition);
}
- for (int s = 0; s < this->numCoverageStages(); ++s) {
- const GrFragmentStage& stage = this->getCoverageStage(s);
- get_stage_stats(stage, &fReadsDst, &fReadsFragPosition);
+ for (int s = firstCoverageStageIdx; s < ds.numCoverageStages(); ++s) {
+ const GrFragmentStage& stage = ds.getCoverageStage(s);
+ get_stage_stats(stage, &descInfo->fReadsDst, &descInfo->fReadsFragPosition);
}
- if (this->hasGeometryProcessor()) {
- const GrGeometryStage& stage = *this->getGeometryProcessor();
- fReadsFragPosition = fReadsFragPosition || stage.getProcessor()->willReadFragmentPosition();
+ if (ds.hasGeometryProcessor()) {
+ const GrGeometryProcessor& gp = *ds.getGeometryProcessor();
+ descInfo->fReadsFragPosition = descInfo->fReadsFragPosition || gp.willReadFragmentPosition();
}
}
+////////////////////////////////////////////////////////////////////////////////
+
bool GrOptDrawState::operator== (const GrOptDrawState& that) const {
return this->isEqual(that);
}
+bool GrOptDrawState::isEqual(const GrOptDrawState& that) const {
+ if (this->fDesc != that.fDesc) {
+ return false;
+ }
+ bool usingVertexColors = that.fDesc.header().fColorAttributeIndex != -1;
+ if (!usingVertexColors && this->fColor != that.fColor) {
+ return false;
+ }
+
+ if (this->getRenderTarget() != that.getRenderTarget() ||
+ !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->fDesc.header().fCoverageAttributeIndex != -1;
+ if (!usingVertexCoverage && this->fCoverage != that.fCoverage) {
+ return false;
+ }
+
+ if (this->hasGeometryProcessor()) {
+ if (!that.hasGeometryProcessor()) {
+ return false;
+ } else if (!this->getGeometryProcessor()->isEqual(*that.getGeometryProcessor())) {
+ return false;
+ }
+ } else if (that.hasGeometryProcessor()) {
+ return false;
+ }
+
+ bool explicitLocalCoords = this->fDesc.header().fLocalCoordAttributeIndex != -1;
+ for (int i = 0; i < this->numFragmentStages(); i++) {
+ if (!GrFragmentStage::AreCompatible(this->getFragmentStage(i), that.getFragmentStage(i),
+ explicitLocalCoords)) {
+ return false;
+ }
+ }
+ return true;
+}
+