R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6624052

git-svn-id: http://skia.googlecode.com/svn/trunk@5838 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2012-10-05 19:04:13 +00:00
Родитель ffca6ce0e2
Коммит c7448cef09
9 изменённых файлов: 163 добавлений и 94 удалений

Просмотреть файл

@ -100,10 +100,7 @@ protected:
ctx->setRenderTarget(target);
GrPaint paint;
paint.reset();
paint.fColor = 0xffffffff;
paint.fSrcBlendCoeff = kOne_GrBlendCoeff;
paint.fDstBlendCoeff = kISA_GrBlendCoeff;
paint.setBlendFunc(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
GrMatrix vm;
if (i) {
vm.setRotate(90 * SK_Scalar1,

Просмотреть файл

@ -17,9 +17,31 @@
#include "SkXfermode.h"
/**
* The paint describes how pixels are colored when the context draws to
* them. TODO: Make this a "real" class with getters and setters, default
* values, and documentation.
* The paint describes how color and coverage are computed at each pixel by GrContext draw
* functions and the how color is blended with the destination pixel.
*
* The paint allows installation of custom color and coverage stages. New types of stages are
* created by subclassing GrCustomStage.
*
* The primitive color computation starts with the color specified by setColor(). This color is the
* input to the first color stage. Each color stage feeds its output to the next color stage. The
* final color stage's output color is input to the color filter specified by
* setXfermodeColorFilter which it turn feeds into the color matrix. The output of the color matrix
* is the final source color, S.
*
* Fractional pixel coverage follows a similar flow. The coverage is initially the value specified
* by setCoverage(). This is input to the first coverage stage. Coverage stages are chained
* together in the same manner as color stages. The output of the last stage is modulated by any
* fractional coverage produced by anti-aliasing. This last step produces the final coverage, C.
*
* setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value
* of the destination pixel, labeled Bs and Bd respectively. The final value of the destination
* pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S).
*
* Note that the coverage is applied after the blend. This is why they are computed as distinct
* values.
*
* TODO: Encapsulate setXfermodeColorFilter and color matrix in stages and remove from GrPaint.
*/
class GrPaint {
public:
@ -28,20 +50,90 @@ public:
kMaxCoverageStages = 1,
};
// All the paint fields are public except textures/samplers
GrBlendCoeff fSrcBlendCoeff;
GrBlendCoeff fDstBlendCoeff;
bool fAntiAlias;
bool fDither;
bool fColorMatrixEnabled;
GrPaint() { this->reset(); }
GrColor fColor;
uint8_t fCoverage;
GrPaint(const GrPaint& paint) { *this = paint; }
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
float fColorMatrix[20];
~GrPaint() {}
/**
* Sets the blending coefficients to use to blend the final primitive color with the
* destination color. Defaults to kOne for src and kZero for dst (i.e. src mode).
*/
void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
fSrcBlendCoeff = srcCoeff;
fDstBlendCoeff = dstCoeff;
}
GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; }
GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; }
/**
* The initial color of the drawn primitive. Defaults to solid white.
*/
void setColor(GrColor color) { fColor = color; }
GrColor getColor() const { return fColor; }
/**
* Applies fractional coverage to the entire drawn primitive. Defaults to 0xff.
*/
void setCoverage(uint8_t coverage) { fCoverage = coverage; }
uint8_t getCoverage() const { return fCoverage; }
/**
* Should primitives be anti-aliased or not. Defaults to false.
*/
void setAntiAlias(bool aa) { fAntiAlias = aa; }
bool isAntiAlias() const { return fAntiAlias; }
/**
* Should dithering be applied. Defaults to false.
*/
void setDither(bool dither) { fDither = dither; }
bool isDither() const { return fDither; }
/**
* Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant
* color passed to this function is considered the "src" color and the primitive's color is
* considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through
* the primitive color unmodified.
*/
void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
fColorFilterColor = color;
fColorFilterXfermode = mode;
}
SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
GrColor getColorFilterColor() const { return fColorFilterColor; }
/**
* Turns off application of a color matrix. By default the color matrix is disabled.
*/
void disableColorMatrix() { fColorMatrixEnabled = false; }
/**
* Specifies and enables a 4 x 5 color matrix.
*/
void setColorMatrix(const float matrix[20]) {
fColorMatrixEnabled = true;
memcpy(fColorMatrix, matrix, sizeof(fColorMatrix));
}
bool isColorMatrixEnabled() const { return fColorMatrixEnabled; }
const float* getColorMatrix() const { return fColorMatrix; }
/**
* Disables both the matrix and SkXfermode::Mode color filters.
*/
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
fColorMatrixEnabled = false;
}
/**
* Specifies a stage of the color pipeline. Usually the texture matrices of color stages apply
* to the primitive's positions. Some GrContext calls take explicit coords as an array or a
* rect. In this case these are the pre-matrix coords to colorSampler(0).
*/
GrSamplerState* colorSampler(int i) {
GrAssert((unsigned)i < kMaxColorStages);
return fColorSamplers + i;
@ -57,8 +149,10 @@ public:
return (NULL != fColorSamplers[i].getCustomStage());
}
// The coverage stage's sampler matrix is always applied to the positions
// (i.e. no explicit texture coordinates)
/**
* Specifies a stage of the coverage pipeline. Coverage stages' texture matrices are always
* applied to the primitive's position, never to explicit texture coords.
*/
GrSamplerState* coverageSampler(int i) {
GrAssert((unsigned)i < kMaxCoverageStages);
return fCoverageSamplers + i;
@ -95,9 +189,9 @@ public:
bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
/**
* Preconcats the matrix of all samplers in the mask with the inverse of a
* matrix. If the matrix inverse cannot be computed (and there is at least
* one enabled stage) then false is returned.
* Preconcats the matrix of all samplers in the mask with the inverse of a matrix. If the
* matrix inverse cannot be computed (and there is at least one enabled stage) then false is
* returned.
*/
bool preConcatSamplerMatricesWithInverse(const GrMatrix& matrix) {
GrMatrix inv;
@ -125,16 +219,6 @@ public:
return true;
}
// uninitialized
GrPaint() {
}
GrPaint(const GrPaint& paint) {
*this = paint;
}
~GrPaint() {}
GrPaint& operator=(const GrPaint& paint) {
fSrcBlendCoeff = paint.fSrcBlendCoeff;
fDstBlendCoeff = paint.fDstBlendCoeff;
@ -164,7 +248,9 @@ public:
return *this;
}
// sets paint to src-over, solid white, no texture, no mask
/**
* Resets the paint to the defaults.
*/
void reset() {
this->resetBlend();
this->resetOptions();
@ -175,12 +261,6 @@ public:
this->resetMasks();
}
void resetColorFilter() {
fColorFilterXfermode = SkXfermode::kDst_Mode;
fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
fColorMatrixEnabled = false;
}
// internal use
// GrPaint's textures and masks map to the first N stages
// of GrDrawTarget in that order (textures followed by masks)
@ -195,6 +275,19 @@ private:
GrSamplerState fColorSamplers[kMaxColorStages];
GrSamplerState fCoverageSamplers[kMaxCoverageStages];
GrBlendCoeff fSrcBlendCoeff;
GrBlendCoeff fDstBlendCoeff;
bool fAntiAlias;
bool fDither;
bool fColorMatrixEnabled;
GrColor fColor;
uint8_t fCoverage;
GrColor fColorFilterColor;
SkXfermode::Mode fColorFilterXfermode;
float fColorMatrix[20];
void resetBlend() {
fSrcBlendCoeff = kOne_GrBlendCoeff;
fDstBlendCoeff = kZero_GrBlendCoeff;

Просмотреть файл

@ -217,7 +217,6 @@ GrTexture* SkBlendImageFilter::onFilterImageGPU(Proxy* proxy, GrTexture* src, co
GrMatrix sampleM;
sampleM.setIDiv(background->width(), background->height());
GrPaint paint;
paint.reset();
paint.colorSampler(0)->reset(sampleM);
paint.colorSampler(0)->setCustomStage(SkNEW_ARGS(GrSingleTextureEffect, (background.get())))->unref();
paint.colorSampler(1)->reset(sampleM);

Просмотреть файл

@ -431,7 +431,6 @@ void apply_morphology_pass(GrContext* context,
GrMatrix sampleM;
sampleM.setIDiv(texture->width(), texture->height());
GrPaint paint;
paint.reset();
paint.colorSampler(0)->reset(sampleM);
paint.colorSampler(0)->setCustomStage(SkNEW_ARGS(GrMorphologyEffect, (texture, direction, radius, morphType)))->unref();
context->drawRect(paint, rect);

Просмотреть файл

@ -613,13 +613,13 @@ void GrContext::drawPaint(const GrPaint& paint) {
am.set(this, GrMatrix::I());
}
// by definition this fills the entire clip, no need for AA
if (paint.fAntiAlias) {
if (paint.isAntiAlias()) {
if (!tmpPaint.isValid()) {
tmpPaint.set(paint);
p = tmpPaint.get();
}
GrAssert(p == tmpPaint.get());
tmpPaint.get()->fAntiAlias = false;
tmpPaint.get()->setAntiAlias(false);
}
this->drawRect(*p, r);
}
@ -736,7 +736,7 @@ void GrContext::drawRect(const GrPaint& paint,
GrRect devRect = rect;
GrMatrix combinedMatrix;
bool useVertexCoverage;
bool needAA = paint.fAntiAlias &&
bool needAA = paint.isAntiAlias() &&
!this->getRenderTarget()->isMultisampled();
bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix,
&combinedMatrix, &devRect,
@ -1013,7 +1013,7 @@ void GrContext::drawOval(const GrPaint& paint,
SkScalar strokeWidth) {
GrAssert(strokeWidth <= 0);
if (!isSimilarityTransformation(this->getMatrix()) ||
!paint.fAntiAlias ||
!paint.isAntiAlias() ||
rect.height() != rect.width()) {
SkPath path;
path.addOval(rect);
@ -1125,7 +1125,7 @@ void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path,
GrDrawTarget* target = this->prepareToDraw(&paint, DEFAULT_BUFFERING);
GrDrawState::AutoStageDisable atr(fDrawState);
bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled();
bool prAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled();
// 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

Просмотреть файл

@ -31,18 +31,18 @@ void GrDrawState::setFromPaint(const GrPaint& paint) {
this->disableStage(s);
}
this->setColor(paint.fColor);
this->setColor(paint.getColor());
this->setState(GrDrawState::kDither_StateBit, paint.fDither);
this->setState(GrDrawState::kHWAntialias_StateBit, paint.fAntiAlias);
this->setState(GrDrawState::kDither_StateBit, paint.isDither());
this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias());
if (paint.fColorMatrixEnabled) {
if (paint.isColorMatrixEnabled()) {
this->enableState(GrDrawState::kColorMatrix_StateBit);
this->setColorMatrix(paint.fColorMatrix);
this->setColorMatrix(paint.getColorMatrix());
} else {
this->disableState(GrDrawState::kColorMatrix_StateBit);
}
this->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff);
this->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode);
this->setCoverage(paint.fCoverage);
this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff());
this->setColorFilter(paint.getColorFilterColor(), paint.getColorFilterMode());
this->setCoverage(paint.getCoverage());
}

Просмотреть файл

@ -38,22 +38,21 @@ void GrTextContext::flushGlyphs() {
drawState->createTextureEffect(kGlyphMaskStage, fCurrTexture, params);
if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
if (kOne_GrBlendCoeff != fPaint.fSrcBlendCoeff ||
kISA_GrBlendCoeff != fPaint.fDstBlendCoeff ||
if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
fPaint.hasColorStage()) {
GrPrintf("LCD Text will not draw correctly.\n");
}
// setup blend so that we get mask * paintColor + (1-mask)*dstColor
drawState->setBlendConstant(fPaint.fColor);
drawState->setBlendConstant(fPaint.getColor());
drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
// don't modulate by the paint's color in the frag since we're
// already doing it via the blend const.
drawState->setColor(0xffffffff);
} else {
// set back to normal in case we took LCD path previously.
drawState->setBlendFunc(fPaint.fSrcBlendCoeff,
fPaint.fDstBlendCoeff);
drawState->setColor(fPaint.fColor);
drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
drawState->setColor(fPaint.getColor());
}
int nGlyphs = fCurrVertex / 4;

Просмотреть файл

@ -510,9 +510,8 @@ inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
SkGpuDevice::SkAutoCachedTexture* act,
GrPaint* grPaint) {
grPaint->fDither = skPaint.isDither();
grPaint->fAntiAlias = skPaint.isAntiAlias();
grPaint->fCoverage = 0xFF;
grPaint->setDither(skPaint.isDither());
grPaint->setAntiAlias(skPaint.isAntiAlias());
SkXfermode::Coeff sm = SkXfermode::kOne_Coeff;
SkXfermode::Coeff dm = SkXfermode::kISA_Coeff;
@ -526,17 +525,16 @@ inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
#endif
}
}
grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm);
grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm);
grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm));
if (justAlpha) {
uint8_t alpha = skPaint.getAlpha();
grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha);
grPaint->setColor(GrColorPackRGBA(alpha, alpha, alpha, alpha));
// justAlpha is currently set to true only if there is a texture,
// so constantColor should not also be true.
GrAssert(!constantColor);
} else {
grPaint->fColor = SkColor2GrColor(skPaint.getColor());
grPaint->setColor(SkColor2GrColor(skPaint.getColor()));
GrAssert(!grPaint->isColorStageEnabled(kShaderTextureIdx));
}
SkColorFilter* colorFilter = skPaint.getColorFilter();
@ -544,24 +542,17 @@ inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
SkXfermode::Mode filterMode;
SkScalar matrix[20];
SkBitmap colorTransformTable;
grPaint->resetColorFilter();
// TODO: SkColorFilter::asCustomStage()
if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) {
grPaint->fColorMatrixEnabled = false;
if (!constantColor) {
grPaint->fColorFilterColor = SkColor2GrColor(color);
grPaint->fColorFilterXfermode = filterMode;
grPaint->setXfermodeColorFilter(filterMode, SkColor2GrColor(color));
} else {
SkColor filtered = colorFilter->filterColor(skPaint.getColor());
grPaint->fColor = SkColor2GrColor(filtered);
grPaint->setColor(SkColor2GrColor(filtered));
}
} else if (colorFilter != NULL && colorFilter->asColorMatrix(matrix)) {
grPaint->fColorMatrixEnabled = true;
memcpy(grPaint->fColorMatrix, matrix, sizeof(matrix));
grPaint->fColorFilterXfermode = SkXfermode::kDst_Mode;
grPaint->setColorMatrix(matrix);
} else if (colorFilter != NULL && colorFilter->asComponentTable(&colorTransformTable)) {
grPaint->resetColorFilter();
// pass NULL because the color table effect doesn't use tiling or filtering.
GrTexture* texture = act->set(dev, colorTransformTable, NULL);
GrSamplerState* colorSampler = grPaint->colorSampler(kColorFilterTextureIdx);
@ -895,18 +886,16 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
context->clear(NULL, 0);
GrPaint tempPaint;
tempPaint.reset();
tempPaint.fAntiAlias = grp->fAntiAlias;
if (tempPaint.fAntiAlias) {
if (grp->isAntiAlias()) {
tempPaint.setAntiAlias(true);
// AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst
// blend coeff of zero requires dual source blending support in order
// to properly blend partially covered pixels. This means the AA
// code path may not be taken. So we use a dst blend coeff of ISA. We
// could special case AA draws to a dst surface with known alpha=0 to
// use a zero dst coeff when dual source blending isn't available.
tempPaint.fSrcBlendCoeff = kOne_GrBlendCoeff;
tempPaint.fDstBlendCoeff = kISC_GrBlendCoeff;
tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
}
// Draw hard shadow to pathTexture with path topleft at origin 0,0.
context->drawPath(tempPaint, path, pathFillType, &offset);
@ -928,18 +917,15 @@ bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path,
(GrSingleTextureEffect, (pathTexture)))->unref();
if (SkMaskFilter::kInner_BlurType == blurType) {
// inner: dst = dst * src
paint.fSrcBlendCoeff = kDC_GrBlendCoeff;
paint.fDstBlendCoeff = kZero_GrBlendCoeff;
paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff);
} else if (SkMaskFilter::kSolid_BlurType == blurType) {
// solid: dst = src + dst - src * dst
// = (1 - dst) * src + 1 * dst
paint.fSrcBlendCoeff = kIDC_GrBlendCoeff;
paint.fDstBlendCoeff = kOne_GrBlendCoeff;
paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff);
} else if (SkMaskFilter::kOuter_BlurType == blurType) {
// outer: dst = dst * (1 - src)
// = 0 * src + (1 - src) * dst
paint.fSrcBlendCoeff = kZero_GrBlendCoeff;
paint.fDstBlendCoeff = kISC_GrBlendCoeff;
paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff);
}
context->drawRect(paint, srcRect);
}
@ -1059,8 +1045,7 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
SkScalar hairlineCoverage;
if (SkDrawTreatAsHairline(paint, *draw.fMatrix, &hairlineCoverage)) {
doFill = false;
grPaint.fCoverage = SkScalarRoundToInt(hairlineCoverage *
grPaint.fCoverage);
grPaint.setCoverage(SkScalarRoundToInt(hairlineCoverage * grPaint.getCoverage()));
}
// If we have a prematrix, apply it to the path, optimizing for the case
@ -1520,7 +1505,6 @@ void apply_custom_stage(GrContext* context,
GrMatrix sampleM;
sampleM.setIDiv(srcTexture->width(), srcTexture->height());
GrPaint paint;
paint.reset();
paint.colorSampler(0)->reset(sampleM);
paint.colorSampler(0)->setCustomStage(stage);
context->drawRect(paint, rect);
@ -1707,7 +1691,6 @@ bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src,
}
GrPaint paint;
paint.reset();
GrTexture* texture;
// We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup

Просмотреть файл

@ -176,7 +176,6 @@ void GrConfigConversionEffect::TestForPreservingPMConversions(GrContext* context
// We then verify that two reads produced the same values.
GrPaint paint;
paint.reset();
SkAutoTUnref<GrCustomStage> pmToUPMStage1(SkNEW_ARGS(GrConfigConversionEffect,
(dataTex, false, *pmToUPMRule)));