Add detection of when partial pixel coverage (for aa or otherwise) will cause incorrect blend
Review URL http://codereview.appspot.com/5112042/ git-svn-id: http://skia.googlecode.com/svn/trunk@2323 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
4f001d8194
commit
d46e2423a7
@ -592,8 +592,7 @@ private:
|
||||
struct OffscreenRecord;
|
||||
|
||||
// determines whether offscreen AA should be applied
|
||||
bool doOffscreenAA(GrDrawTarget* target,
|
||||
const GrPaint& paint,
|
||||
bool doOffscreenAA(GrDrawTarget* target,
|
||||
bool isHairLines) const;
|
||||
|
||||
// attempts to setup offscreen AA. All paint state must be transferred to
|
||||
|
@ -29,6 +29,10 @@
|
||||
|
||||
#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB)
|
||||
|
||||
// When we're using coverage AA but the blend is incompatible (given gpu
|
||||
// limitations) should we disable AA or draw wrong?
|
||||
#define DISABLE_COVERAGE_AA_FOR_BLEND 0
|
||||
|
||||
static const size_t MAX_TEXTURE_CACHE_COUNT = 256;
|
||||
static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024;
|
||||
|
||||
@ -632,6 +636,12 @@ void GrContext::drawPaint(const GrPaint& paint) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) {
|
||||
return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage();
|
||||
}
|
||||
}
|
||||
|
||||
struct GrContext::OffscreenRecord {
|
||||
enum Downsample {
|
||||
k4x4TwoPass_Downsample,
|
||||
@ -650,12 +660,11 @@ struct GrContext::OffscreenRecord {
|
||||
};
|
||||
|
||||
bool GrContext::doOffscreenAA(GrDrawTarget* target,
|
||||
const GrPaint& paint,
|
||||
bool isHairLines) const {
|
||||
#if !GR_USE_OFFSCREEN_AA
|
||||
return false;
|
||||
#else
|
||||
if (!paint.fAntiAlias) {
|
||||
if (!target->isAntialiasState()) {
|
||||
return false;
|
||||
}
|
||||
// Line primitves are always rasterized as 1 pixel wide.
|
||||
@ -667,14 +676,7 @@ bool GrContext::doOffscreenAA(GrDrawTarget* target,
|
||||
if (target->getRenderTarget()->isMultisampled()) {
|
||||
return false;
|
||||
}
|
||||
// we have to be sure that the blend equation is expressible
|
||||
// as simple src / dst coeffecients when the source
|
||||
// is already modulated by the coverage fraction.
|
||||
// We could use dual-source blending to get the correct per-pixel
|
||||
// dst coeffecient for the remaining cases.
|
||||
if (kISC_BlendCoeff != paint.fDstBlendCoeff &&
|
||||
kOne_BlendCoeff != paint.fDstBlendCoeff &&
|
||||
kISA_BlendCoeff != paint.fDstBlendCoeff) {
|
||||
if (disable_coverage_aa_for_blend(target)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1139,7 +1141,6 @@ static bool isIRect(const GrRect& r) {
|
||||
}
|
||||
|
||||
static bool apply_aa_to_rect(GrDrawTarget* target,
|
||||
const GrPaint& paint,
|
||||
const GrRect& rect,
|
||||
GrScalar width,
|
||||
const GrMatrix* matrix,
|
||||
@ -1150,7 +1151,11 @@ static bool apply_aa_to_rect(GrDrawTarget* target,
|
||||
// will be axis-aligned,the render target is not
|
||||
// multisampled, and the rect won't land on integer coords.
|
||||
|
||||
if (!paint.fAntiAlias) {
|
||||
if (!target->isAntialiasState()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!target->canTweakAlphaForCoverage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1198,7 +1203,7 @@ void GrContext::drawRect(const GrPaint& paint,
|
||||
|
||||
GrRect devRect = rect;
|
||||
GrMatrix combinedMatrix;
|
||||
bool doAA = apply_aa_to_rect(target, paint, rect, width, matrix,
|
||||
bool doAA = apply_aa_to_rect(target, rect, width, matrix,
|
||||
&combinedMatrix, &devRect);
|
||||
|
||||
if (doAA) {
|
||||
@ -1440,6 +1445,15 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
|
||||
GrPathFill fill, const GrPoint* translate) {
|
||||
|
||||
GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory);
|
||||
|
||||
// An Assumption here is that path renderer would use some form of tweaking
|
||||
// the src color (either the input alpha or in the frag shader) to implement
|
||||
// aa. If we have some future driver-mojo path AA that can do the right
|
||||
// thing WRT to the blend then we'll need some query on the PR.
|
||||
if (disable_coverage_aa_for_blend(target)) {
|
||||
target->disableState(GrDrawTarget::kAntialias_StateBit);
|
||||
}
|
||||
|
||||
GrPathRenderer* pr = this->getPathRenderer(target, path, fill);
|
||||
if (NULL == pr) {
|
||||
GrPrintf("Unable to find path renderer compatible with path.\n");
|
||||
@ -1450,7 +1464,7 @@ void GrContext::drawPath(const GrPaint& paint, const GrPath& path,
|
||||
GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask();
|
||||
|
||||
if (!pr->supportsAA(target, path, fill) &&
|
||||
this->doOffscreenAA(target, paint, kHairLine_PathFill == fill)) {
|
||||
this->doOffscreenAA(target, kHairLine_PathFill == fill)) {
|
||||
|
||||
bool needsStencil = pr->requiresStencilPass(target, path, fill);
|
||||
|
||||
@ -1666,6 +1680,10 @@ void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) {
|
||||
}
|
||||
target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
|
||||
target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
|
||||
|
||||
if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
|
||||
GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
|
||||
}
|
||||
}
|
||||
|
||||
GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint,
|
||||
|
@ -744,6 +744,25 @@ 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) {
|
||||
/**
|
||||
* The fractional coverage is f
|
||||
* The src and dst coeffs are Cs and Cd
|
||||
* The dst and src colors are S and D
|
||||
* We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D
|
||||
* By tweaking the source color's alpha we're replacing S with S'=fS. It's
|
||||
* obvious that that first term will always be ok. The second term can be
|
||||
* rearranged as [1-(1-Cd)f]D. By substituing in the various possbilities
|
||||
* 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;
|
||||
}
|
||||
|
||||
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.
|
||||
@ -808,9 +827,15 @@ bool GrDrawTarget::CanUseHWAALines(GrVertexLayout layout, const DrState& state)
|
||||
// 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.
|
||||
// is 0xff and tweaking the color for partial coverage is OK
|
||||
return (kAntialias_StateBit & state.fFlagBits) &&
|
||||
CanDisableBlend(layout, state);
|
||||
CanDisableBlend(layout, state) &&
|
||||
CanTweakAlphaForCoverage(state.fDstBlend);
|
||||
}
|
||||
|
||||
bool GrDrawTarget::canApplyCoverage() const {
|
||||
return this->getCaps().fDualSourceBlendingSupport ||
|
||||
CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
|
||||
}
|
||||
|
||||
bool GrDrawTarget::canDisableBlend() const {
|
||||
|
@ -595,6 +595,28 @@ public:
|
||||
*/
|
||||
bool canDisableBlend() const;
|
||||
|
||||
/**
|
||||
* Color alpha and coverage are two inputs to the drawing pipeline. For some
|
||||
* blend modes it is safe to fold the coverage into constant or per-vertex
|
||||
* color alpha value. For other blend modes they must be handled separately.
|
||||
* Depending on features available in the underlying 3D API this may or may
|
||||
* not be possible.
|
||||
*
|
||||
* This function looks at the current blend on the draw target and the draw
|
||||
* target's capabilities to determine whether coverage can be handled
|
||||
* correctly.
|
||||
*/
|
||||
bool canApplyCoverage() const;
|
||||
|
||||
/**
|
||||
* Determines whether incorporating partial pixel coverage into the constant
|
||||
* color specified by setColor or per-vertex colors will give the right
|
||||
* blending result.
|
||||
*/
|
||||
bool canTweakAlphaForCoverage() const {
|
||||
return CanTweakAlphaForCoverage(fCurrDrawState.fDstBlend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the interpretation per-vertex edge data when the
|
||||
* kEdge_VertexLayoutBit is set (see below). When per-vertex edges are not
|
||||
@ -1227,6 +1249,10 @@ 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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user