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:
bsalomon@google.com 2011-10-12 14:54:26 +00:00
parent d9f2dea532
commit 86c1f71625
16 changed files with 388 additions and 166 deletions

View File

@ -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;

View File

@ -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); \
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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());
}
///////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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";

View File

@ -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

View File

@ -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();

View File

@ -219,7 +219,6 @@ public:
void removeResource(GrResource* resource);
// GrDrawTarget overrides
virtual bool willUseHWAALines() const;
virtual void clear(const GrIRect* rect, GrColor color);
protected:

View File

@ -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));

View File

@ -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);

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -91,8 +91,6 @@ public:
virtual void clear(const GrIRect* rect, GrColor color);
virtual bool willUseHWAALines() const;
private:
struct Draw {