Gpu blend optimizations, handle more xfer modes with fractional pixel coverage
Review URL: http://codereview.appspot.com/5237062/ git-svn-id: http://skia.googlecode.com/svn/trunk@2464 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
d9f2dea532
commit
86c1f71625
@ -154,6 +154,16 @@ struct GrStencilSettings {
|
||||
kAlways_StencilFunc == fFrontFunc &&
|
||||
kAlways_StencilFunc == fBackFunc;
|
||||
}
|
||||
bool doesWrite() const {
|
||||
return !((kNever_StencilFunc == fFrontFunc ||
|
||||
kKeep_StencilOp == fFrontPassOp) &&
|
||||
(kNever_StencilFunc == fBackFunc ||
|
||||
kKeep_StencilOp == fBackPassOp) &&
|
||||
(kAlways_StencilFunc == fFrontFunc ||
|
||||
kKeep_StencilOp == fFrontFailOp) &&
|
||||
(kAlways_StencilFunc == fBackFunc ||
|
||||
kKeep_StencilOp == fBackFailOp));
|
||||
}
|
||||
void invalidate() {
|
||||
// just write an illegal value to the first member
|
||||
fFrontPassOp = (GrStencilOp)-1;
|
||||
|
@ -21,22 +21,32 @@
|
||||
* bitfield.
|
||||
*/
|
||||
#define GR_MAKE_BITFIELD_OPS(X) \
|
||||
static inline X operator | (X a, X b) { \
|
||||
inline X operator | (X a, X b) { \
|
||||
return (X) (+a | +b); \
|
||||
} \
|
||||
\
|
||||
static inline X operator & (X a, X b) { \
|
||||
inline X operator & (X a, X b) { \
|
||||
return (X) (+a & +b); \
|
||||
} \
|
||||
template <typename T> \
|
||||
static inline X operator & (T a, X b) { \
|
||||
inline X operator & (T a, X b) { \
|
||||
return (X) (+a & +b); \
|
||||
} \
|
||||
template <typename T> \
|
||||
static inline X operator & (X a, T b) { \
|
||||
inline X operator & (X a, T b) { \
|
||||
return (X) (+a & +b); \
|
||||
} \
|
||||
|
||||
#define GR_DECL_BITFIELD_OPS_FRIENDS(X) \
|
||||
friend X operator | (X a, X b); \
|
||||
\
|
||||
friend X operator & (X a, X b); \
|
||||
\
|
||||
template <typename T> \
|
||||
friend X operator & (T a, X b); \
|
||||
\
|
||||
template <typename T> \
|
||||
friend X operator & (X a, T b); \
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
@ -179,7 +179,7 @@ static inline bool single_pass_path(const GrDrawTarget& target,
|
||||
return hint == kConvex_ConvexHint ||
|
||||
hint == kNonOverlappingConvexPieces_ConvexHint ||
|
||||
(hint == kSameWindingConvexPieces_ConvexHint &&
|
||||
target.canDisableBlend() && !target.isDitherState());
|
||||
!target.drawWillReadDst() && !target.isDitherState());
|
||||
|
||||
}
|
||||
return false;
|
||||
|
@ -825,7 +825,7 @@ void GrDrawTarget::drawNonIndexed(GrPrimitiveType type,
|
||||
|
||||
// Some blend modes allow folding a partial coverage value into the color's
|
||||
// alpha channel, while others will blend incorrectly.
|
||||
bool GrDrawTarget::CanTweakAlphaForCoverage(GrBlendCoeff dstCoeff) {
|
||||
bool GrDrawTarget::canTweakAlphaForCoverage() const {
|
||||
/**
|
||||
* The fractional coverage is f
|
||||
* The src and dst coeffs are Cs and Cd
|
||||
@ -837,89 +837,186 @@ bool GrDrawTarget::CanTweakAlphaForCoverage(GrBlendCoeff dstCoeff) {
|
||||
* for Cd we find that only 1, ISA, and ISC produce the correct depth
|
||||
* coeffecient in terms of S' and D.
|
||||
*/
|
||||
return kOne_BlendCoeff == dstCoeff ||
|
||||
kISA_BlendCoeff == dstCoeff ||
|
||||
kISC_BlendCoeff == dstCoeff;
|
||||
return kOne_BlendCoeff == fCurrDrawState.fDstBlend||
|
||||
kISA_BlendCoeff == fCurrDrawState.fDstBlend ||
|
||||
kISC_BlendCoeff == fCurrDrawState.fDstBlend;
|
||||
}
|
||||
|
||||
bool GrDrawTarget::CanDisableBlend(GrVertexLayout layout, const DrState& state) {
|
||||
// If we compute a coverage value (using edge AA or a coverage stage) then
|
||||
// we can't force blending off.
|
||||
if (state.fEdgeAANumEdges > 0 ||
|
||||
(layout & kEdge_VertexLayoutBit) ||
|
||||
(layout & kCoverage_VertexLayoutBit)) {
|
||||
return false;
|
||||
}
|
||||
for (int s = state.fFirstCoverageStage; s < kNumStages; ++s) {
|
||||
if (StageWillBeUsed(s, layout, state)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((kOne_BlendCoeff == state.fSrcBlend) &&
|
||||
(kZero_BlendCoeff == state.fDstBlend)) {
|
||||
return true;
|
||||
}
|
||||
bool GrDrawTarget::srcAlphaWillBeOne() const {
|
||||
const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
|
||||
|
||||
// If we have vertex color without alpha then we can't force blend off
|
||||
// Check if per-vertex or constant color may have partial alpha
|
||||
if ((layout & kColor_VertexLayoutBit) ||
|
||||
0xff != GrColorUnpackA(state.fColor)) {
|
||||
0xff != GrColorUnpackA(fCurrDrawState.fColor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the src coef will always be 1...
|
||||
if (kSA_BlendCoeff != state.fSrcBlend &&
|
||||
kOne_BlendCoeff != state.fSrcBlend) {
|
||||
// Check if color filter could introduce an alpha
|
||||
// (TODO: Consider being more aggressive with regards to detecting 0xff
|
||||
// final alpha from color filter).
|
||||
if (SkXfermode::kDst_Mode != fCurrDrawState.fColorFilterXfermode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...and the dst coef is always 0...
|
||||
if (kISA_BlendCoeff != state.fDstBlend &&
|
||||
kZero_BlendCoeff != state.fDstBlend) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...and there isn't a texture stage with an alpha channel...
|
||||
for (int s = 0; s < state.fFirstCoverageStage; ++s) {
|
||||
if (StageWillBeUsed(s, layout, state)) {
|
||||
GrAssert(NULL != state.fTextures[s]);
|
||||
|
||||
GrPixelConfig config = state.fTextures[s]->config();
|
||||
|
||||
// Check if a color stage could create a partial alpha
|
||||
for (int s = 0; s < fCurrDrawState.fFirstCoverageStage; ++s) {
|
||||
if (StageWillBeUsed(s, layout, fCurrDrawState)) {
|
||||
GrAssert(NULL != fCurrDrawState.fTextures[s]);
|
||||
GrPixelConfig config = fCurrDrawState.fTextures[s]->config();
|
||||
if (!GrPixelConfigIsOpaque(config)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ...and there isn't an interesting color filter...
|
||||
// TODO: Consider being more aggressive with regards to disabling
|
||||
// blending when a color filter is used.
|
||||
if (SkXfermode::kDst_Mode != state.fColorFilterXfermode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...then we disable blend.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrDrawTarget::CanUseHWAALines(GrVertexLayout layout, const DrState& state) {
|
||||
GrDrawTarget::BlendOptFlags
|
||||
GrDrawTarget::getBlendOpts(bool forceCoverage,
|
||||
GrBlendCoeff* srcCoeff,
|
||||
GrBlendCoeff* dstCoeff) const {
|
||||
|
||||
const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout;
|
||||
|
||||
GrBlendCoeff bogusSrcCoeff, bogusDstCoeff;
|
||||
if (NULL == srcCoeff) {
|
||||
srcCoeff = &bogusSrcCoeff;
|
||||
}
|
||||
*srcCoeff = fCurrDrawState.fSrcBlend;
|
||||
|
||||
if (NULL == dstCoeff) {
|
||||
dstCoeff = &bogusDstCoeff;
|
||||
}
|
||||
*dstCoeff = fCurrDrawState.fDstBlend;
|
||||
|
||||
// We don't ever expect source coeffecients to reference the source
|
||||
GrAssert(kSA_BlendCoeff != *srcCoeff &&
|
||||
kISA_BlendCoeff != *srcCoeff &&
|
||||
kSC_BlendCoeff != *srcCoeff &&
|
||||
kISC_BlendCoeff != *srcCoeff);
|
||||
// same for dst
|
||||
GrAssert(kDA_BlendCoeff != *dstCoeff &&
|
||||
kIDA_BlendCoeff != *dstCoeff &&
|
||||
kDC_BlendCoeff != *dstCoeff &&
|
||||
kIDC_BlendCoeff != *dstCoeff);
|
||||
|
||||
if (SkToBool(kNoColorWrites_StateBit & fCurrDrawState.fFlagBits)) {
|
||||
*srcCoeff = kZero_BlendCoeff;
|
||||
*dstCoeff = kOne_BlendCoeff;
|
||||
}
|
||||
|
||||
bool srcAIsOne = this->srcAlphaWillBeOne();
|
||||
bool dstCoeffIsOne = kOne_BlendCoeff == *dstCoeff ||
|
||||
(kSA_BlendCoeff == *dstCoeff && srcAIsOne);
|
||||
bool dstCoeffIsZero = kZero_BlendCoeff == *dstCoeff ||
|
||||
(kISA_BlendCoeff == *dstCoeff && srcAIsOne);
|
||||
|
||||
|
||||
// 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).
|
||||
if ((kZero_BlendCoeff == *srcCoeff && dstCoeffIsOne)) {
|
||||
if (fCurrDrawState.fStencilSettings.doesWrite()) {
|
||||
if (fCaps.fShaderSupport) {
|
||||
return kDisableBlend_BlendOptFlag |
|
||||
kEmitTransBlack_BlendOptFlag;
|
||||
} else {
|
||||
return kDisableBlend_BlendOptFlag;
|
||||
}
|
||||
} else {
|
||||
return kSkipDraw_BlendOptFlag;
|
||||
}
|
||||
}
|
||||
|
||||
// check for coverage due to edge aa or coverage texture stage
|
||||
bool hasCoverage = forceCoverage ||
|
||||
fCurrDrawState.fEdgeAANumEdges > 0 ||
|
||||
(layout & kCoverage_VertexLayoutBit) ||
|
||||
(layout & kEdge_VertexLayoutBit);
|
||||
for (int s = fCurrDrawState.fFirstCoverageStage;
|
||||
!hasCoverage && s < kNumStages;
|
||||
++s) {
|
||||
if (StageWillBeUsed(s, layout, fCurrDrawState)) {
|
||||
hasCoverage = true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have coverage we can check whether the dst
|
||||
// has to read at all. If not, we'll disable blending.
|
||||
if (!hasCoverage) {
|
||||
if (dstCoeffIsZero) {
|
||||
if (kOne_BlendCoeff == *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;
|
||||
} else if (kZero_BlendCoeff == *srcCoeff &&
|
||||
fCaps.fShaderSupport) {
|
||||
// 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_BlendCoeff;
|
||||
*dstCoeff = kZero_BlendCoeff;
|
||||
return kDisableBlend_BlendOptFlag |
|
||||
kEmitTransBlack_BlendOptFlag;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check whether coverage can be safely rolled into alpha
|
||||
// of if we can skip color computation and just emit coverage
|
||||
if (this->canTweakAlphaForCoverage()) {
|
||||
return kCoverageAsAlpha_BlendOptFlag;
|
||||
}
|
||||
// We haven't implemented support for these optimizations in the
|
||||
// fixed pipe (which is on its deathbed)
|
||||
if (fCaps.fShaderSupport) {
|
||||
if (dstCoeffIsZero) {
|
||||
if (kZero_BlendCoeff == *srcCoeff) {
|
||||
// the source color is not included in the blend
|
||||
// the dst coeff is effectively zero so blend works out to:
|
||||
// (c)(0)D + (1-c)D = (1-c)D.
|
||||
*dstCoeff = kISA_BlendCoeff;
|
||||
return kEmitCoverage_BlendOptFlag;
|
||||
} else if (srcAIsOne) {
|
||||
// the dst coeff is effectively zero so blend works out to:
|
||||
// cS + (c)(0)D + (1-c)D = cS + (1-c)D.
|
||||
// If Sa is 1 then we can replace Sa with c
|
||||
// and set dst coeff to 1-Sa.
|
||||
*dstCoeff = kISA_BlendCoeff;
|
||||
return kCoverageAsAlpha_BlendOptFlag;
|
||||
}
|
||||
} else if (dstCoeffIsOne) {
|
||||
// the dst coeff is effectively one so blend works out to:
|
||||
// cS + (c)(1)D + (1-c)D = cS + D.
|
||||
*dstCoeff = kOne_BlendCoeff;
|
||||
return kCoverageAsAlpha_BlendOptFlag;
|
||||
}
|
||||
}
|
||||
}
|
||||
return kNone_BlendOpt;
|
||||
}
|
||||
|
||||
bool GrDrawTarget::willUseHWAALines() const {
|
||||
// there is a conflict between using smooth lines and our use of
|
||||
// premultiplied alpha. Smooth lines tweak the incoming alpha value
|
||||
// but not in a premul-alpha way. So we only use them when our alpha
|
||||
// is 0xff and tweaking the color for partial coverage is OK
|
||||
return (kAntialias_StateBit & state.fFlagBits) &&
|
||||
CanDisableBlend(layout, state) &&
|
||||
CanTweakAlphaForCoverage(state.fDstBlend);
|
||||
if (!fCaps.fHWAALineSupport ||
|
||||
!(kAntialias_StateBit & fCurrDrawState.fFlagBits)) {
|
||||
return false;
|
||||
}
|
||||
BlendOptFlags opts = this->getBlendOpts();
|
||||
return (kDisableBlend_BlendOptFlag & opts) &&
|
||||
(kCoverageAsAlpha_BlendOptFlag & opts);
|
||||
}
|
||||
|
||||
bool GrDrawTarget::canApplyCoverage() const {
|
||||
// we can correctly apply coverage if a) we have dual source blending
|
||||
// or b) one of our blend optimizations applies.
|
||||
return this->getCaps().fDualSourceBlendingSupport ||
|
||||
CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
|
||||
kNone_BlendOpt != this->getBlendOpts(true);
|
||||
}
|
||||
|
||||
bool GrDrawTarget::canDisableBlend() const {
|
||||
return CanDisableBlend(this->getGeomSrc().fVertexLayout, fCurrDrawState);
|
||||
bool GrDrawTarget::drawWillReadDst() const {
|
||||
return SkToBool((kDisableBlend_BlendOptFlag | kSkipDraw_BlendOptFlag) &
|
||||
this->getBlendOpts());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -131,7 +131,6 @@ public:
|
||||
// pairs for convexity while
|
||||
// rasterizing. Set this if the
|
||||
// source polygon is non-convex.
|
||||
|
||||
// subclass may use additional bits internally
|
||||
kDummyStateBit,
|
||||
kLastPublicStateBit = kDummyStateBit-1
|
||||
@ -524,13 +523,13 @@ public:
|
||||
GrColor getBlendConstant() const { return fCurrDrawState.fBlendConstant; }
|
||||
|
||||
/**
|
||||
* Determines if blend is effectively disabled.
|
||||
* Determines if blending will require a read of a dst given the current
|
||||
* state set on the draw target
|
||||
*
|
||||
* @return true if blend can be disabled without changing the rendering
|
||||
* result given the current state including the vertex layout specified
|
||||
* with the vertex source.
|
||||
* @return true if the dst surface will be read at each pixel hit by the
|
||||
* a draw operation.
|
||||
*/
|
||||
bool canDisableBlend() const;
|
||||
bool drawWillReadDst() const;
|
||||
|
||||
/**
|
||||
* Color alpha and coverage are two inputs to the drawing pipeline. For some
|
||||
@ -550,9 +549,7 @@ public:
|
||||
* color specified by setColor or per-vertex colors will give the right
|
||||
* blending result.
|
||||
*/
|
||||
bool canTweakAlphaForCoverage() const {
|
||||
return CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
|
||||
}
|
||||
bool canTweakAlphaForCoverage() const;
|
||||
|
||||
/**
|
||||
* Determines the interpretation per-vertex edge data when the
|
||||
@ -568,7 +565,7 @@ public:
|
||||
* lines be used (if line primitive type is drawn)? (Note that lines are
|
||||
* always 1 pixel wide)
|
||||
*/
|
||||
virtual bool willUseHWAALines() const = 0;
|
||||
bool willUseHWAALines() const;
|
||||
|
||||
/**
|
||||
* Sets the edge data required for edge antialiasing.
|
||||
@ -653,6 +650,7 @@ public:
|
||||
|
||||
private:
|
||||
static const int TEX_COORD_BIT_CNT = kNumStages*kMaxTexCoords;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Generates a bit indicating that a texture stage uses the position
|
||||
@ -1299,15 +1297,57 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
// Determines whether it is correct to apply partial pixel coverage
|
||||
// by multiplying the src color by the fractional coverage.
|
||||
static bool CanTweakAlphaForCoverage(GrBlendCoeff dstCoeff);
|
||||
|
||||
// determines whether HW blending can be disabled or not
|
||||
static bool CanDisableBlend(GrVertexLayout layout, const DrState& state);
|
||||
/**
|
||||
* Optimizations for blending / coverage to be applied based on the current
|
||||
* state.
|
||||
* Subclasses that actually draw (as opposed to those that just buffer for
|
||||
* playback) must implement the flags that replace the output color.
|
||||
*/
|
||||
enum BlendOptFlags {
|
||||
/**
|
||||
* No optimization
|
||||
*/
|
||||
kNone_BlendOpt = 0,
|
||||
/**
|
||||
* Don't draw at all
|
||||
*/
|
||||
kSkipDraw_BlendOptFlag = 0x2,
|
||||
/**
|
||||
* Emit the src color, disable HW blending (replace dst with src)
|
||||
*/
|
||||
kDisableBlend_BlendOptFlag = 0x4,
|
||||
/**
|
||||
* The coverage value does not have to be computed separately from
|
||||
* alpha, the the output color can be the modulation of the two.
|
||||
*/
|
||||
kCoverageAsAlpha_BlendOptFlag = 0x1,
|
||||
/**
|
||||
* Instead of emitting a src color, emit coverage in the alpha channel
|
||||
* and r,g,b are "don't cares".
|
||||
*/
|
||||
kEmitCoverage_BlendOptFlag = 0x10,
|
||||
/**
|
||||
* Emit transparent black instead of the src color, no need to compute
|
||||
* coverage.
|
||||
*/
|
||||
kEmitTransBlack_BlendOptFlag = 0x8,
|
||||
};
|
||||
GR_DECL_BITFIELD_OPS_FRIENDS(BlendOptFlags);
|
||||
|
||||
// determines whether HW AA lines can be used or not
|
||||
static bool CanUseHWAALines(GrVertexLayout layout, const DrState& state);
|
||||
// Determines what optimizations can be applied based on the blend.
|
||||
// The coeffecients may have to be tweaked in order for the optimization
|
||||
// to work. srcCoeff and dstCoeff are optional params that receive the
|
||||
// tweaked coeffecients.
|
||||
// Normally the function looks at the current state to see if coverage
|
||||
// is enabled. By setting forceCoverage the caller can speculatively
|
||||
// determine the blend optimizations that would be used if there was
|
||||
// partial pixel coverage
|
||||
BlendOptFlags getBlendOpts(bool forceCoverage = false,
|
||||
GrBlendCoeff* srcCoeff = NULL,
|
||||
GrBlendCoeff* dstCoeff = NULL) const;
|
||||
|
||||
// determine if src alpha is guaranteed to be one for all src pixels
|
||||
bool srcAlphaWillBeOne() const;
|
||||
|
||||
enum GeometrySrcType {
|
||||
kNone_GeometrySrcType, //<! src has not been specified
|
||||
@ -1431,4 +1471,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
GR_MAKE_BITFIELD_OPS(GrDrawTarget::BlendOptFlags);
|
||||
|
||||
#endif
|
||||
|
@ -598,6 +598,20 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
|
||||
uniformCoeff = SkXfermode::kZero_Coeff;
|
||||
}
|
||||
|
||||
// If we know the final color is going to be all zeros then we can
|
||||
// simplify the color filter coeffecients. needComputedColor will then
|
||||
// come out false below.
|
||||
if (ProgramDesc::kTransBlack_ColorType == fProgramDesc.fColorType) {
|
||||
colorCoeff = SkXfermode::kZero_Coeff;
|
||||
if (SkXfermode::kDC_Coeff == uniformCoeff ||
|
||||
SkXfermode::kDA_Coeff == uniformCoeff) {
|
||||
uniformCoeff = SkXfermode::kZero_Coeff;
|
||||
} else if (SkXfermode::kIDC_Coeff == uniformCoeff ||
|
||||
SkXfermode::kIDA_Coeff == uniformCoeff) {
|
||||
uniformCoeff = SkXfermode::kOne_Coeff;
|
||||
}
|
||||
}
|
||||
|
||||
bool needColorFilterUniform;
|
||||
bool needComputedColor;
|
||||
needBlendInputs(uniformCoeff, colorCoeff,
|
||||
@ -645,8 +659,13 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
|
||||
programData->fUniLocations.fColorUni = kUseUniform;
|
||||
inColor = COL_UNI_NAME;
|
||||
break;
|
||||
case ProgramDesc::kTransBlack_ColorType:
|
||||
GrAssert(!"needComputedColor should be false.");
|
||||
break;
|
||||
case ProgramDesc::kSolidWhite_ColorType:
|
||||
break;
|
||||
default:
|
||||
GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType);
|
||||
GrCrash("Unknown color type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -708,15 +727,18 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
|
||||
}
|
||||
}
|
||||
|
||||
// if have all ones for the "dst" input to the color filter then we can make
|
||||
// additional optimizations.
|
||||
if (needColorFilterUniform && !inColor.size() &&
|
||||
(SkXfermode::kIDC_Coeff == uniformCoeff ||
|
||||
SkXfermode::kIDA_Coeff == uniformCoeff)) {
|
||||
uniformCoeff = SkXfermode::kZero_Coeff;
|
||||
bool bogus;
|
||||
needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
|
||||
&needColorFilterUniform, &bogus);
|
||||
// if have all ones or zeros for the "dst" input to the color filter then we
|
||||
// may be able to make additional optimizations.
|
||||
if (needColorFilterUniform && needComputedColor && !inColor.size()) {
|
||||
GrAssert(ProgramDesc::kSolidWhite_ColorType == fProgramDesc.fColorType);
|
||||
bool uniformCoeffIsZero = SkXfermode::kIDC_Coeff == uniformCoeff ||
|
||||
SkXfermode::kIDA_Coeff == uniformCoeff;
|
||||
if (uniformCoeffIsZero) {
|
||||
uniformCoeff = SkXfermode::kZero_Coeff;
|
||||
bool bogus;
|
||||
needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff,
|
||||
&needColorFilterUniform, &bogus);
|
||||
}
|
||||
}
|
||||
if (needColorFilterUniform) {
|
||||
segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
|
||||
@ -733,7 +755,16 @@ bool GrGLProgram::genProgram(const GrGLInterface* gl,
|
||||
wroteFragColorZero = true;
|
||||
} else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) {
|
||||
segments.fFSCode.appendf("\tvec4 filteredColor;\n");
|
||||
const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4);
|
||||
const char* color;
|
||||
if (inColor.size()) {
|
||||
color = inColor.c_str();
|
||||
} else {
|
||||
if (ProgramDesc::kSolidWhite_ColorType == fProgramDesc.fColorType) {
|
||||
color = all_ones_vec(4);
|
||||
} else {
|
||||
color = all_zeros_vec(4);
|
||||
}
|
||||
}
|
||||
addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff,
|
||||
colorCoeff, color);
|
||||
inColor = "filteredColor";
|
||||
|
@ -139,10 +139,15 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
// Specifies where the intitial color comes from before the stages are
|
||||
// applied.
|
||||
enum ColorType {
|
||||
kNone_ColorType = 0,
|
||||
kAttribute_ColorType = 1,
|
||||
kUniform_ColorType = 2,
|
||||
kSolidWhite_ColorType,
|
||||
kTransBlack_ColorType,
|
||||
kAttribute_ColorType,
|
||||
kUniform_ColorType,
|
||||
|
||||
kColorTypeCnt
|
||||
};
|
||||
// Dual-src blending makes use of a secondary output color that can be
|
||||
// used as a per-pixel blend coeffecient. This controls whether a
|
||||
|
@ -140,13 +140,6 @@ void GrGpu::unimpl(const char msg[]) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GrGpu::willUseHWAALines() const {
|
||||
return (kAntialias_StateBit & fCurrDrawState.fFlagBits) &&
|
||||
CanUseHWAALines(this->getGeomSrc().fVertexLayout, fCurrDrawState);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrTexture* GrGpu::createTexture(const GrTextureDesc& desc,
|
||||
const void* srcData, size_t rowBytes) {
|
||||
this->handleDirtyContext();
|
||||
|
@ -219,7 +219,6 @@ public:
|
||||
void removeResource(GrResource* resource);
|
||||
|
||||
// GrDrawTarget overrides
|
||||
virtual bool willUseHWAALines() const;
|
||||
virtual void clear(const GrIRect* rect, GrColor color);
|
||||
|
||||
protected:
|
||||
|
@ -1811,8 +1811,8 @@ void GrGpuGL::flushAAState(GrPrimitiveType type) {
|
||||
}
|
||||
}
|
||||
|
||||
void GrGpuGL::flushBlend(GrPrimitiveType type,
|
||||
GrBlendCoeff srcCoeff,
|
||||
void GrGpuGL::flushBlend(GrPrimitiveType type,
|
||||
GrBlendCoeff srcCoeff,
|
||||
GrBlendCoeff dstCoeff) {
|
||||
if (GrIsPrimTypeLines(type) && this->willUseHWAALines()) {
|
||||
if (fHWBlendDisabled) {
|
||||
@ -1827,7 +1827,11 @@ void GrGpuGL::flushBlend(GrPrimitiveType type,
|
||||
fHWDrawState.fDstBlend = kISA_BlendCoeff;
|
||||
}
|
||||
} else {
|
||||
bool blendOff = canDisableBlend();
|
||||
// any optimization to disable blending should
|
||||
// have already been applied and tweaked the coeffs
|
||||
// to (1, 0).
|
||||
bool blendOff = kOne_BlendCoeff == srcCoeff &&
|
||||
kZero_BlendCoeff == dstCoeff;
|
||||
if (fHWBlendDisabled != blendOff) {
|
||||
if (blendOff) {
|
||||
GL_CALL(Disable(GR_GL_BLEND));
|
||||
|
@ -123,7 +123,10 @@ protected:
|
||||
// line width
|
||||
bool flushGLStateCommon(GrPrimitiveType type);
|
||||
|
||||
// subclass should call this to flush the blend state
|
||||
// Subclasses should call this to flush the blend state.
|
||||
// The params should be the final coeffecients to apply
|
||||
// (after any blending optimizations or dual source blending considerations
|
||||
// have been accounted for).
|
||||
void flushBlend(GrPrimitiveType type,
|
||||
GrBlendCoeff srcCoeff,
|
||||
GrBlendCoeff dstCoeff);
|
||||
|
@ -172,7 +172,13 @@ bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->flushBlend(type, fCurrDrawState.fSrcBlend, fCurrDrawState.fDstBlend);
|
||||
GrBlendCoeff srcCoeff, dstCoeff;
|
||||
if (kSkipDraw_BlendOptFlag &
|
||||
this->getBlendOpts(false, &srcCoeff, &dstCoeff)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->flushBlend(type, srcCoeff, dstCoeff);
|
||||
|
||||
if (fDirtyFlags.fRenderTargetChanged) {
|
||||
flushProjectionMatrix();
|
||||
|
@ -204,14 +204,8 @@ bool GrGpuGLShaders::programUnitTest() {
|
||||
|
||||
pdesc.fVertexLayout = 0;
|
||||
pdesc.fEmitsPointSize = random.nextF() > .5f;
|
||||
float colorType = random.nextF();
|
||||
if (colorType < 1.f / 3.f) {
|
||||
pdesc.fColorType = ProgramDesc::kAttribute_ColorType;
|
||||
} else if (colorType < 2.f / 3.f) {
|
||||
pdesc.fColorType = ProgramDesc::kUniform_ColorType;
|
||||
} else {
|
||||
pdesc.fColorType = ProgramDesc::kNone_ColorType;
|
||||
}
|
||||
pdesc.fColorType = static_cast<int>(random.nextF() *
|
||||
ProgramDesc::kColorTypeCnt);
|
||||
|
||||
int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt));
|
||||
pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx;
|
||||
@ -589,7 +583,7 @@ static const float ONE_OVER_255 = 1.f / 255.f;
|
||||
GrColorUnpackA(color) * ONE_OVER_255 \
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::flushColor() {
|
||||
void GrGpuGLShaders::flushColor(GrColor color) {
|
||||
const ProgramDesc& desc = fCurrentProgram.getDesc();
|
||||
if (this->getGeomSrc().fVertexLayout & kColor_VertexLayoutBit) {
|
||||
// color will be specified per-vertex as an attribute
|
||||
@ -598,27 +592,27 @@ void GrGpuGLShaders::flushColor() {
|
||||
} else {
|
||||
switch (desc.fColorType) {
|
||||
case ProgramDesc::kAttribute_ColorType:
|
||||
if (fHWDrawState.fColor != fCurrDrawState.fColor) {
|
||||
if (fHWDrawState.fColor != color) {
|
||||
// OpenGL ES only supports the float varities of glVertexAttrib
|
||||
float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
|
||||
float c[] = GR_COLOR_TO_VEC4(color);
|
||||
GL_CALL(VertexAttrib4fv(GrGLProgram::ColorAttributeIdx(),
|
||||
c));
|
||||
fHWDrawState.fColor = fCurrDrawState.fColor;
|
||||
fHWDrawState.fColor = color;
|
||||
}
|
||||
break;
|
||||
case ProgramDesc::kUniform_ColorType:
|
||||
if (fProgramData->fColor != fCurrDrawState.fColor) {
|
||||
if (fProgramData->fColor != color) {
|
||||
// OpenGL ES only supports the float varities of glVertexAttrib
|
||||
float c[] = GR_COLOR_TO_VEC4(fCurrDrawState.fColor);
|
||||
float c[] = GR_COLOR_TO_VEC4(color);
|
||||
GrAssert(GrGLProgram::kUnusedUniform !=
|
||||
fProgramData->fUniLocations.fColorUni);
|
||||
GL_CALL(Uniform4fv(fProgramData->fUniLocations.fColorUni,
|
||||
1, c));
|
||||
fProgramData->fColor = fCurrDrawState.fColor;
|
||||
fProgramData->fColor = color;
|
||||
}
|
||||
break;
|
||||
case ProgramDesc::kNone_ColorType:
|
||||
GrAssert(0xffffffff == fCurrDrawState.fColor);
|
||||
case ProgramDesc::kSolidWhite_ColorType:
|
||||
case ProgramDesc::kTransBlack_ColorType:
|
||||
break;
|
||||
default:
|
||||
GrCrash("Unknown color type.");
|
||||
@ -648,7 +642,14 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
|
||||
fProgramCache->invalidateViewMatrices();
|
||||
}
|
||||
|
||||
buildProgram(type);
|
||||
GrBlendCoeff srcCoeff;
|
||||
GrBlendCoeff dstCoeff;
|
||||
BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff);
|
||||
if (kSkipDraw_BlendOptFlag & blendOpts) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->buildProgram(type, blendOpts, dstCoeff);
|
||||
fProgramData = fProgramCache->getProgramData(fCurrentProgram);
|
||||
if (NULL == fProgramData) {
|
||||
GrAssert(!"Failed to create program!");
|
||||
@ -659,13 +660,18 @@ bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) {
|
||||
GL_CALL(UseProgram(fProgramData->fProgramID));
|
||||
fHWProgramID = fProgramData->fProgramID;
|
||||
}
|
||||
GrBlendCoeff srcCoeff = fCurrDrawState.fSrcBlend;
|
||||
GrBlendCoeff dstCoeff = fCurrDrawState.fDstBlend;
|
||||
|
||||
fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff);
|
||||
this->flushBlend(type, srcCoeff, dstCoeff);
|
||||
|
||||
this->flushColor();
|
||||
GrColor color;
|
||||
if (blendOpts & kEmitTransBlack_BlendOptFlag) {
|
||||
color = 0;
|
||||
} else if (blendOpts & kEmitCoverage_BlendOptFlag) {
|
||||
color = 0xffffffff;
|
||||
} else {
|
||||
color = fCurrDrawState.fColor;
|
||||
}
|
||||
this->flushColor(color);
|
||||
|
||||
GrMatrix* currViewMatrix;
|
||||
if (GrGLProgram::kSetAsAttribute ==
|
||||
@ -836,9 +842,19 @@ void GrGpuGLShaders::setupGeometry(int* startVertex,
|
||||
fHWGeometryState.fArrayPtrsDirty = false;
|
||||
}
|
||||
|
||||
void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
void GrGpuGLShaders::buildProgram(GrPrimitiveType type,
|
||||
BlendOptFlags blendOpts,
|
||||
GrBlendCoeff dstCoeff) {
|
||||
ProgramDesc& desc = fCurrentProgram.fProgramDesc;
|
||||
|
||||
// This should already have been caught
|
||||
GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts));
|
||||
|
||||
bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
|
||||
|
||||
bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag |
|
||||
kEmitCoverage_BlendOptFlag));
|
||||
|
||||
// The descriptor is used as a cache key. Thus when a field of the
|
||||
// descriptor will not affect program generation (because of the vertex
|
||||
// layout in use or other descriptor field settings) it should be set
|
||||
@ -849,35 +865,47 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
|
||||
desc.fEmitsPointSize = kPoints_PrimitiveType == type;
|
||||
|
||||
bool requiresAttributeColors = 0 != (desc.fVertexLayout & kColor_VertexLayoutBit);
|
||||
bool requiresAttributeColors =
|
||||
!skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit);
|
||||
// fColorType records how colors are specified for the program. Strip
|
||||
// the bit from the layout to avoid false negatives when searching for an
|
||||
// existing program in the cache.
|
||||
desc.fVertexLayout &= ~(kColor_VertexLayoutBit);
|
||||
|
||||
desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode;
|
||||
desc.fColorFilterXfermode = skipColor ?
|
||||
SkXfermode::kDst_Mode :
|
||||
fCurrDrawState.fColorFilterXfermode;
|
||||
|
||||
#if GR_AGGRESSIVE_SHADER_OPTS
|
||||
if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) {
|
||||
desc.fColorType = ProgramDesc::kNone_ColorType;
|
||||
} else
|
||||
#endif
|
||||
#if GR_GL_NO_CONSTANT_ATTRIBUTES
|
||||
if (!requiresAttributeColors) {
|
||||
// no reason to do edge aa or look at per-vertex coverage if coverage is
|
||||
// ignored
|
||||
if (skipCoverage) {
|
||||
desc.fVertexLayout &= ~(kEdge_VertexLayoutBit |
|
||||
kCoverage_VertexLayoutBit);
|
||||
}
|
||||
|
||||
bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag);
|
||||
bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) ||
|
||||
(!requiresAttributeColors &&
|
||||
0xffffffff == fCurrDrawState.fColor);
|
||||
if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) {
|
||||
desc.fColorType = ProgramDesc::kTransBlack_ColorType;
|
||||
} else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) {
|
||||
desc.fColorType = ProgramDesc::kSolidWhite_ColorType;
|
||||
} else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) {
|
||||
desc.fColorType = ProgramDesc::kUniform_ColorType;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (requiresAttributeColors) {} // suppress unused var warning
|
||||
} else {
|
||||
desc.fColorType = ProgramDesc::kAttribute_ColorType;
|
||||
}
|
||||
|
||||
desc.fEdgeAANumEdges = fCurrDrawState.fEdgeAANumEdges;
|
||||
desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit);
|
||||
desc.fEdgeAANumEdges = skipCoverage ? 0 : fCurrDrawState.fEdgeAANumEdges;
|
||||
desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 &&
|
||||
SkToBool(fCurrDrawState.fFlagBits &
|
||||
kEdgeAAConcave_StateBit);
|
||||
|
||||
int lastEnabledStage = -1;
|
||||
|
||||
if (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit) {
|
||||
if (!skipCoverage && (desc.fVertexLayout &
|
||||
GrDrawTarget::kEdge_VertexLayoutBit)) {
|
||||
desc.fVertexEdgeType = fCurrDrawState.fVertexEdgeType;
|
||||
} else {
|
||||
// use canonical value when not set to avoid cache misses
|
||||
@ -890,7 +918,10 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
stage.fOptFlags = 0;
|
||||
stage.setEnabled(this->isStageEnabled(s));
|
||||
|
||||
if (stage.isEnabled()) {
|
||||
bool skip = s < fCurrDrawState.fFirstCoverageStage ? skipColor :
|
||||
skipCoverage;
|
||||
|
||||
if (!skip && stage.isEnabled()) {
|
||||
lastEnabledStage = s;
|
||||
GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s];
|
||||
GrAssert(NULL != texture);
|
||||
@ -1005,22 +1036,19 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) {
|
||||
desc.fFirstCoverageStage = firstCoverageStage;
|
||||
}
|
||||
|
||||
// We could consider cases where the final color is solid (0xff alpha)
|
||||
// and the dst coeff can correctly be set to a non-dualsrc gl value.
|
||||
// (e.g. solid draw, and dst coeff is kZero. It's correct to make
|
||||
// the dst coeff be kISA. Or solid draw with kSA can be tweaked to be
|
||||
// kOne).
|
||||
if (this->getCaps().fDualSourceBlendingSupport) {
|
||||
if (kZero_BlendCoeff == fCurrDrawState.fDstBlend) {
|
||||
if (this->getCaps().fDualSourceBlendingSupport &&
|
||||
!(blendOpts & (kEmitCoverage_BlendOptFlag |
|
||||
kCoverageAsAlpha_BlendOptFlag))) {
|
||||
if (kZero_BlendCoeff == dstCoeff) {
|
||||
// write the coverage value to second color
|
||||
desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput;
|
||||
desc.fFirstCoverageStage = firstCoverageStage;
|
||||
} else if (kSA_BlendCoeff == fCurrDrawState.fDstBlend) {
|
||||
} else if (kSA_BlendCoeff == dstCoeff) {
|
||||
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
|
||||
// cover
|
||||
desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput;
|
||||
desc.fFirstCoverageStage = firstCoverageStage;
|
||||
} else if (kSC_BlendCoeff == fCurrDrawState.fDstBlend) {
|
||||
} else if (kSC_BlendCoeff == dstCoeff) {
|
||||
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially
|
||||
// cover
|
||||
desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput;
|
||||
|
@ -57,7 +57,7 @@ private:
|
||||
void flushTextureDomain(int stage);
|
||||
|
||||
// sets the color specified by GrDrawTarget::setColor()
|
||||
void flushColor();
|
||||
void flushColor(GrColor color);
|
||||
|
||||
// sets the MVP matrix uniform for currently bound program
|
||||
void flushViewMatrix();
|
||||
@ -77,7 +77,9 @@ private:
|
||||
static void DeleteProgram(const GrGLInterface* gl,
|
||||
CachedData* programData);
|
||||
|
||||
void buildProgram(GrPrimitiveType type);
|
||||
void buildProgram(GrPrimitiveType typeBlend,
|
||||
BlendOptFlags blendOpts,
|
||||
GrBlendCoeff dstCoeff);
|
||||
|
||||
ProgramCache* fProgramCache;
|
||||
CachedData* fProgramData;
|
||||
|
@ -616,9 +616,3 @@ void GrInOrderDrawBuffer::clipWillBeSet(const GrClip& newClip) {
|
||||
INHERITED::clipWillBeSet(newClip);
|
||||
fClipSet = true;
|
||||
}
|
||||
|
||||
bool GrInOrderDrawBuffer::willUseHWAALines() const {
|
||||
return this->getCaps().fHWAALineSupport &&
|
||||
CanUseHWAALines(this->getGeomSrc().fVertexLayout, fCurrDrawState);
|
||||
}
|
||||
|
||||
|
@ -91,8 +91,6 @@ public:
|
||||
|
||||
virtual void clear(const GrIRect* rect, GrColor color);
|
||||
|
||||
virtual bool willUseHWAALines() const;
|
||||
|
||||
private:
|
||||
|
||||
struct Draw {
|
||||
|
Loading…
Reference in New Issue
Block a user