/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrInvariantOutput_DEFINED #define GrInvariantOutput_DEFINED #include "GrColor.h" /** * This describes the color or coverage input that will be seen by the first color or coverage stage * of a GrPipeline. This is also the GrPrimitiveProcessor color or coverage *output*. */ struct GrPipelineInput { GrPipelineInput() : fValidFlags(kNone_GrColorComponentFlags) , fColor(0) , fIsSingleComponent(false) , fIsLCDCoverage(false) {} void setKnownFourComponents(GrColor color) { fColor = color; fValidFlags = kRGBA_GrColorComponentFlags; fIsSingleComponent = false; } void setUnknownFourComponents() { fValidFlags = kNone_GrColorComponentFlags; fIsSingleComponent = false; } void setUnknownOpaqueFourComponents() { fColor = 0xffU << GrColor_SHIFT_A; fValidFlags = kA_GrColorComponentFlag; fIsSingleComponent = false; } void setKnownSingleComponent(uint8_t alpha) { fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha); fValidFlags = kRGBA_GrColorComponentFlags; fIsSingleComponent = true; } void setUnknownSingleComponent() { fValidFlags = kNone_GrColorComponentFlags; fIsSingleComponent = true; } void setUsingLCDCoverage() { fIsLCDCoverage = true; } GrColorComponentFlags fValidFlags; GrColor fColor; bool fIsSingleComponent; bool fIsLCDCoverage; // Temorary data member until texture pixel configs are // updated }; /** This describes the output of a GrFragmentProcessor in a GrPipeline. */ class GrInvariantOutput { public: GrInvariantOutput(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) : fColor(color) , fValidFlags(flags) , fIsSingleComponent(isSingleComponent) , fNonMulStageFound(false) , fWillUseInputColor(true) , fIsLCDCoverage(false) {} GrInvariantOutput(const GrPipelineInput& input) : fColor(input.fColor) , fValidFlags(input.fValidFlags) , fIsSingleComponent(input.fIsSingleComponent) , fNonMulStageFound(false) , fWillUseInputColor(false) , fIsLCDCoverage(input.fIsLCDCoverage) {} virtual ~GrInvariantOutput() {} enum ReadInput { kWill_ReadInput, kWillNot_ReadInput, }; void mulByUnknownOpaqueFourComponents() { SkDEBUGCODE(this->validate()); if (this->isOpaque()) { fValidFlags = kA_GrColorComponentFlag; fIsSingleComponent = false; } else { // Since the current state is not opaque we no longer care if the color being // multiplied is opaque. this->mulByUnknownFourComponents(); } SkDEBUGCODE(this->validate()); } void mulByUnknownFourComponents() { SkDEBUGCODE(this->validate()); if (this->hasZeroAlpha()) { this->internalSetToTransparentBlack(); } else { this->internalSetToUnknown(); } SkDEBUGCODE(this->validate()); } void mulByUnknownSingleComponent() { SkDEBUGCODE(this->validate()); if (this->hasZeroAlpha()) { this->internalSetToTransparentBlack(); } else { // We don't need to change fIsSingleComponent in this case fValidFlags = kNone_GrColorComponentFlags; } SkDEBUGCODE(this->validate()); } void mulByKnownSingleComponent(uint8_t alpha) { SkDEBUGCODE(this->validate()); if (this->hasZeroAlpha() || 0 == alpha) { this->internalSetToTransparentBlack(); } else { if (alpha != 255) { // Multiply color by alpha fColor = GrColorPackRGBA(SkMulDiv255Round(GrColorUnpackR(fColor), alpha), SkMulDiv255Round(GrColorUnpackG(fColor), alpha), SkMulDiv255Round(GrColorUnpackB(fColor), alpha), SkMulDiv255Round(GrColorUnpackA(fColor), alpha)); // We don't need to change fIsSingleComponent in this case } } SkDEBUGCODE(this->validate()); } void mulByKnownFourComponents(GrColor color) { SkDEBUGCODE(this->validate()); uint32_t a; if (GetAlphaAndCheckSingleChannel(color, &a)) { this->mulByKnownSingleComponent(a); } else { if (color != 0xffffffff) { fColor = GrColorPackRGBA( SkMulDiv255Round(GrColorUnpackR(fColor), GrColorUnpackR(color)), SkMulDiv255Round(GrColorUnpackG(fColor), GrColorUnpackG(color)), SkMulDiv255Round(GrColorUnpackB(fColor), GrColorUnpackB(color)), SkMulDiv255Round(GrColorUnpackA(fColor), a)); if (kRGBA_GrColorComponentFlags == fValidFlags) { fIsSingleComponent = GetAlphaAndCheckSingleChannel(fColor, &a); } } } SkDEBUGCODE(this->validate()); } // Ignores the incoming color's RGB and muls its alpha by color. void mulAlphaByKnownFourComponents(GrColor color) { SkDEBUGCODE(this->validate()); uint32_t a; if (GetAlphaAndCheckSingleChannel(color, &a)) { this->mulAlphaByKnownSingleComponent(a); } else if (fValidFlags & kA_GrColorComponentFlag) { GrColor preAlpha = GrColorUnpackA(fColor); if (0 == preAlpha) { this->internalSetToTransparentBlack(); } else { // We know that color has different component values fIsSingleComponent = false; fColor = GrColorPackRGBA( SkMulDiv255Round(preAlpha, GrColorUnpackR(color)), SkMulDiv255Round(preAlpha, GrColorUnpackG(color)), SkMulDiv255Round(preAlpha, GrColorUnpackB(color)), SkMulDiv255Round(preAlpha, a)); fValidFlags = kRGBA_GrColorComponentFlags; } } else { fIsSingleComponent = false; fValidFlags = kNone_GrColorComponentFlags; } SkDEBUGCODE(this->validate()); } // Ignores the incoming color's RGB and muls its alpha by the alpha param and sets all channels // equal to that value. void mulAlphaByKnownSingleComponent(uint8_t alpha) { SkDEBUGCODE(this->validate()); if (0 == alpha || this->hasZeroAlpha()) { this->internalSetToTransparentBlack(); } else { if (fValidFlags & kA_GrColorComponentFlag) { GrColor a = GrColorUnpackA(fColor); a = SkMulDiv255Round(alpha, a); fColor = GrColorPackRGBA(a, a, a, a); fValidFlags = kRGBA_GrColorComponentFlags; } else { fValidFlags = kNone_GrColorComponentFlags; } fIsSingleComponent = true; } SkDEBUGCODE(this->validate()); } void premulFourChannelColor() { SkDEBUGCODE(this->validate()); SkASSERT(!fIsSingleComponent); fNonMulStageFound = true; if (!(fValidFlags & kA_GrColorComponentFlag)) { fValidFlags = kNone_GrColorComponentFlags; } else { fColor = GrPremulColor(fColor); } SkDEBUGCODE(this->validate()); } void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) { SkDEBUGCODE(this->validate()); fValidFlags = (fValidFlags & ~invalidateFlags); fIsSingleComponent = false; fNonMulStageFound = true; if (kWillNot_ReadInput == readsInput) { fWillUseInputColor = false; } SkDEBUGCODE(this->validate()); } void setToOther(GrColorComponentFlags validFlags, GrColor color, ReadInput readsInput) { SkDEBUGCODE(this->validate()); fValidFlags = validFlags; fColor = color; fIsSingleComponent = false; fNonMulStageFound = true; if (kWillNot_ReadInput == readsInput) { fWillUseInputColor = false; } if (kRGBA_GrColorComponentFlags == fValidFlags) { uint32_t a; if (GetAlphaAndCheckSingleChannel(color, &a)) { fIsSingleComponent = true; } } SkDEBUGCODE(this->validate()); } void setToUnknown(ReadInput readsInput) { SkDEBUGCODE(this->validate()); this->internalSetToUnknown(); fNonMulStageFound= true; if (kWillNot_ReadInput == readsInput) { fWillUseInputColor = false; } SkDEBUGCODE(this->validate()); } // Temporary setter to handle LCD text correctly until we improve texture pixel config queries // and thus can rely solely on number of coverage components for RGA vs single channel coverage. void setUsingLCDCoverage() { fIsLCDCoverage = true; } GrColor color() const { return fColor; } GrColorComponentFlags validFlags() const { return fValidFlags; } bool willUseInputColor() const { return fWillUseInputColor; } /** * If isSingleComponent is true, then the flag values for r, g, b, and a must all be the * same. If the flags are all set then all color components must be equal. */ SkDEBUGCODE(void validate() const;) private: friend class GrProcOptInfo; /** Extracts the alpha channel and returns true if r,g,b == a. */ static bool GetAlphaAndCheckSingleChannel(GrColor color, uint32_t* alpha) { *alpha = GrColorUnpackA(color); return *alpha == GrColorUnpackR(color) && *alpha == GrColorUnpackG(color) && *alpha == GrColorUnpackB(color); } void reset(GrColor color, GrColorComponentFlags flags, bool isSingleComponent) { fColor = color; fValidFlags = flags; fIsSingleComponent = isSingleComponent; fNonMulStageFound = false; fWillUseInputColor = true; } void reset(const GrPipelineInput& input) { fColor = input.fColor; fValidFlags = input.fValidFlags; fIsSingleComponent = input.fIsSingleComponent; fNonMulStageFound = false; fWillUseInputColor = true; fIsLCDCoverage = input.fIsLCDCoverage; } void internalSetToTransparentBlack() { fValidFlags = kRGBA_GrColorComponentFlags; fColor = 0; fIsSingleComponent = true; } void internalSetToUnknown() { fValidFlags = kNone_GrColorComponentFlags; fIsSingleComponent = false; } bool hasZeroAlpha() const { return ((fValidFlags & kA_GrColorComponentFlag) && 0 == GrColorUnpackA(fColor)); } bool isOpaque() const { return ((fValidFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(fColor)); } bool isSolidWhite() const { return (fValidFlags == kRGBA_GrColorComponentFlags && 0xFFFFFFFF == fColor); } bool isSingleComponent() const { return fIsSingleComponent; } void resetWillUseInputColor() { fWillUseInputColor = true; } bool allStagesMulInput() const { return !fNonMulStageFound; } void resetNonMulStageFound() { fNonMulStageFound = false; } bool isLCDCoverage() const { return fIsLCDCoverage; } SkDEBUGCODE(bool colorComponentsAllEqual() const;) /** * If alpha is valid, check that any valid R,G,B values are <= A */ SkDEBUGCODE(bool validPreMulColor() const;) GrColor fColor; GrColorComponentFlags fValidFlags; bool fIsSingleComponent; bool fNonMulStageFound; bool fWillUseInputColor; bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated }; #endif