Pull xfer mode test out of generic draw-as-hairline test. Use coverage rather than alpha to draw hairlines < 1pix wide in GPU.

Review URL: http://codereview.appspot.com/5528112/




git-svn-id: http://skia.googlecode.com/svn/trunk@3070 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-01-18 20:34:00 +00:00
parent 376cd1f919
commit dd1be60702
5 changed files with 59 additions and 54 deletions

View File

@ -36,6 +36,7 @@ public:
bool fColorMatrixEnabled;
GrColor fColor;
uint8_t fCoverage;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
@ -126,6 +127,7 @@ public:
fDither = paint.fDither;
fColor = paint.fColor;
fCoverage = paint.fCoverage;
fColorFilterColor = paint.fColorFilterColor;
fColorFilterXfermode = paint.fColorFilterXfermode;
@ -161,6 +163,7 @@ public:
this->resetBlend();
this->resetOptions();
this->resetColor();
this->resetCoverage();
this->resetTextures();
this->resetColorFilter();
this->resetMasks();
@ -242,6 +245,10 @@ private:
fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
}
void resetCoverage() {
fCoverage = 0xff;
}
void resetTextures() {
for (int i = 0; i < kMaxTextures; ++i) {
this->setTexture(i, NULL);

View File

@ -860,14 +860,14 @@ static bool xfermodeSupportsCoverageAsAlpha(SkXfermode* xfer) {
}
bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
SkAlpha* newAlpha) {
SkASSERT(newAlpha);
SkScalar* coverage) {
SkASSERT(coverage);
if (SkPaint::kStroke_Style != paint.getStyle()) {
return false;
}
SkScalar strokeWidth = paint.getStrokeWidth();
if (0 == strokeWidth) {
*newAlpha = paint.getAlpha();
*coverage = SK_Scalar1;
return true;
}
@ -877,9 +877,6 @@ bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
if (!paint.isAntiAlias()) {
return false;
}
if (!xfermodeSupportsCoverageAsAlpha(paint.getXfermode())) {
return false;
}
if (matrix.hasPerspective()) {
return false;
}
@ -891,16 +888,7 @@ bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
SkScalar len0 = fast_len(dst[0]);
SkScalar len1 = fast_len(dst[1]);
if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
SkScalar modulate = SkScalarAve(len0, len1);
#if 0
*newAlpha = SkToU8(SkScalarRoundToInt(modulate * paint.getAlpha()));
#else
// this is the old technique, which we preserve for now so we don't
// change previous results (testing)
// the new way seems fine, its just (a tiny bit) different
int scale = (int)SkScalarMul(modulate, 256);
*newAlpha = paint.getAlpha() * scale >> 8;
#endif
*coverage = SkScalarAve(len0, len1);
return true;
}
return false;
@ -947,12 +935,29 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
SkTLazy<SkPaint> lazyPaint;
{
SkAlpha newAlpha;
if (SkDrawTreatAsHairline(origPaint, *matrix, &newAlpha)) {
lazyPaint.set(origPaint);
lazyPaint.get()->setAlpha(newAlpha);
lazyPaint.get()->setStrokeWidth(0);
paint = lazyPaint.get();
SkScalar coverage;
if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
if (SK_Scalar1 == coverage) {
lazyPaint.set(origPaint);
lazyPaint.get()->setStrokeWidth(0);
paint = lazyPaint.get();
} else if (xfermodeSupportsCoverageAsAlpha(origPaint.getXfermode())) {
U8CPU newAlpha;
#if 0
newAlpha = SkToU8(SkScalarRoundToInt(coverage *
origPaint.getAlpha()));
#else
// this is the old technique, which we preserve for now so
// we don't change previous results (testing)
// the new way seems fine, its just (a tiny bit) different
int scale = (int)SkScalarMul(coverage, 256);
newAlpha = origPaint.getAlpha() * scale >> 8;
#endif
lazyPaint.set(origPaint);
lazyPaint.get()->setStrokeWidth(0);
lazyPaint.get()->setAlpha(newAlpha);
paint = lazyPaint.get();
}
}
}

View File

@ -35,13 +35,12 @@ struct SkDrawProcs {
};
/**
* If the current paint is set to stroke, has a compatible xfermode, and the
* stroke-width when applied to the matrix is <= 1.0, then this returns true,
* and sets newAlpha (simulating a stroke by drawing a hairline + newAlpha).
* If any of these conditions are false, then this returns false and modulate
* is ignored.
* If the current paint is set to stroke and the stroke-width when applied to
* the matrix is <= 1.0, then this returns true, and sets coverage (simulating
* a stroke by drawing a hairline with partial coverage). If any of these
* conditions are false, then this returns false and coverage is ignored.
*/
bool SkDrawTreatAsHairline(const SkPaint&, const SkMatrix&, SkAlpha* newAlpha);
bool SkDrawTreatAsHairline(const SkPaint&, const SkMatrix&, SkScalar* coverage);
#endif

View File

@ -2060,6 +2060,7 @@ void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) {
drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
drawState->setColorMatrix(paint.fColorMatrix);
drawState->setCoverage(paint.fCoverage);
if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) {
GrPrintf("Partial pixel coverage will be incorrectly blended.\n");
@ -2254,6 +2255,9 @@ void GrContext::convolve(GrTexture* texture,
GrDrawTarget::AutoStateRestore asr(fGpu);
GrDrawState* drawState = fGpu->drawState();
GrRenderTarget* target = drawState->getRenderTarget();
drawState->reset();
drawState->setRenderTarget(target);
GrMatrix sampleM;
sampleM.setIDiv(texture->width(), texture->height());
drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
@ -2263,10 +2267,7 @@ void GrContext::convolve(GrTexture* texture,
kernel,
imageIncrement);
drawState->setViewMatrix(GrMatrix::I());
drawState->setTexture(0, texture);
drawState->setAlpha(0xFF);
drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff);
fGpu->drawSimpleRect(rect, NULL, 1 << 0);
}

View File

@ -412,6 +412,7 @@ bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint,
grPaint->fDither = skPaint.isDither();
grPaint->fAntiAlias = skPaint.isAntiAlias();
grPaint->fCoverage = 0xFF;
SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
@ -1061,32 +1062,22 @@ static bool drawWithMaskFilter(GrContext* context, const SkPath& path,
}
void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
const SkPaint& origPaint, const SkMatrix* prePathMatrix,
const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
CHECK_SHOULD_DRAW(draw);
bool doFill = true;
SkTLazy<SkPaint> lazyPaint;
const SkPaint* paint = &origPaint;
// can we cheat, and threat a thin stroke as a hairline (w/ modulated alpha)
SkScalar coverage = SK_Scalar1;
// can we cheat, and threat a thin stroke as a hairline w/ coverage
// if we can, we draw lots faster (raster device does this same test)
{
SkAlpha newAlpha;
if (SkDrawTreatAsHairline(*paint, *draw.fMatrix, &newAlpha)) {
lazyPaint.set(*paint);
lazyPaint.get()->setAlpha(newAlpha);
lazyPaint.get()->setStrokeWidth(0);
paint = lazyPaint.get();
doFill = false;
}
if (SkDrawTreatAsHairline(paint, *draw.fMatrix, &coverage)) {
doFill = false;
}
// must reference paint from here down, and not origPaint
// since we may have change the paint (using lazyPaint for storage)
GrPaint grPaint;
SkAutoCachedTexture act;
if (!this->skPaint2GrPaintShader(*paint,
if (!this->skPaint2GrPaintShader(paint,
&act,
*draw.fMatrix,
&grPaint,
@ -1094,6 +1085,8 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
return;
}
grPaint.fCoverage = SkScalarRoundToInt(coverage * grPaint.fCoverage);
// If we have a prematrix, apply it to the path, optimizing for the case
// where the original path can in fact be modified in place (even though
// its parameter type is const).
@ -1115,25 +1108,25 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
// at this point we're done with prePathMatrix
SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
if (doFill && (paint->getPathEffect() ||
paint->getStyle() != SkPaint::kFill_Style)) {
if (doFill && (paint.getPathEffect() ||
paint.getStyle() != SkPaint::kFill_Style)) {
// it is safe to use tmpPath here, even if we already used it for the
// prepathmatrix, since getFillPath can take the same object for its
// input and output safely.
doFill = paint->getFillPath(*pathPtr, &tmpPath);
doFill = paint.getFillPath(*pathPtr, &tmpPath);
pathPtr = &tmpPath;
}
if (paint->getMaskFilter()) {
if (paint.getMaskFilter()) {
// avoid possibly allocating a new path in transform if we can
SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
// transform the path into device space
pathPtr->transform(*draw.fMatrix, devPathPtr);
if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint->getMaskFilter(),
if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
*draw.fMatrix, *draw.fClip, draw.fBounder,
&grPaint)) {
drawWithMaskFilter(fContext, *devPathPtr, paint->getMaskFilter(),
drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(),
*draw.fMatrix, *draw.fClip, draw.fBounder,
&grPaint);
}