diff options
-rw-r--r-- | gm/texdata.cpp | 5 | ||||
-rw-r--r-- | include/gpu/GrPaint.h | 165 | ||||
-rw-r--r-- | src/effects/SkBlendImageFilter.cpp | 1 | ||||
-rw-r--r-- | src/effects/SkMorphologyImageFilter.cpp | 1 | ||||
-rw-r--r-- | src/gpu/GrContext.cpp | 10 | ||||
-rw-r--r-- | src/gpu/GrDrawState.cpp | 16 | ||||
-rw-r--r-- | src/gpu/GrTextContext.cpp | 11 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 47 | ||||
-rw-r--r-- | src/gpu/effects/GrConfigConversionEffect.cpp | 1 |
9 files changed, 163 insertions, 94 deletions
diff --git a/gm/texdata.cpp b/gm/texdata.cpp index a87be453ea..724b4ec826 100644 --- a/gm/texdata.cpp +++ b/gm/texdata.cpp @@ -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, diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h index 9b07a4be16..9f9403e9e7 100644 --- a/include/gpu/GrPaint.h +++ b/include/gpu/GrPaint.h @@ -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; diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp index f1714003b9..1388e336dc 100644 --- a/src/effects/SkBlendImageFilter.cpp +++ b/src/effects/SkBlendImageFilter.cpp @@ -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); diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp index 7a4f5a9dbf..e00d94a754 100644 --- a/src/effects/SkMorphologyImageFilter.cpp +++ b/src/effects/SkMorphologyImageFilter.cpp @@ -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); diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index d6e0b508eb..3e53c19ff8 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -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 diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index bd6e2685bb..f798cda59c 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -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()); } diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp index 5c8b9e50d3..c245401d9a 100644 --- a/src/gpu/GrTextContext.cpp +++ b/src/gpu/GrTextContext.cpp @@ -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; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index a792977ff8..b0b5ed0453 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -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 diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp index 3af0979be9..b9c9f63ae3 100644 --- a/src/gpu/effects/GrConfigConversionEffect.cpp +++ b/src/gpu/effects/GrConfigConversionEffect.cpp @@ -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))); |