Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #ifndef GrPaint_DEFINED
     11 #define GrPaint_DEFINED
     12 
     13 #include "GrColor.h"
     14 #include "GrEffectStage.h"
     15 
     16 #include "SkXfermode.h"
     17 
     18 /**
     19  * The paint describes how color and coverage are computed at each pixel by GrContext draw
     20  * functions and the how color is blended with the destination pixel.
     21  *
     22  * The paint allows installation of custom color and coverage stages. New types of stages are
     23  * created by subclassing GrEffect.
     24  *
     25  * The primitive color computation starts with the color specified by setColor(). This color is the
     26  * input to the first color stage. Each color stage feeds its output to the next color stage. The
     27  * final color stage's output color is input to the color filter specified by
     28  * setXfermodeColorFilter which produces the final source color, S.
     29  *
     30  * Fractional pixel coverage follows a similar flow. The coverage is initially the value specified
     31  * by setCoverage(). This is input to the first coverage stage. Coverage stages are chained
     32  * together in the same manner as color stages. The output of the last stage is modulated by any
     33  * fractional coverage produced by anti-aliasing. This last step produces the final coverage, C.
     34  *
     35  * setBlendFunc() specifies blending coefficients for S (described above) and D, the initial value
     36  * of the destination pixel, labeled Bs and Bd respectively. The final value of the destination
     37  * pixel is then D' = (1-C)*D + C*(Bd*D + Bs*S).
     38  *
     39  * Note that the coverage is applied after the blend. This is why they are computed as distinct
     40  * values.
     41  *
     42  * TODO: Encapsulate setXfermodeColorFilter in a GrEffect and remove from GrPaint.
     43  */
     44 class GrPaint {
     45 public:
     46     enum {
     47         kMaxColorStages     = 2,
     48         kMaxCoverageStages  = 1,
     49     };
     50 
     51     GrPaint() { this->reset(); }
     52 
     53     GrPaint(const GrPaint& paint) { *this = paint; }
     54 
     55     ~GrPaint() {}
     56 
     57     /**
     58      * Sets the blending coefficients to use to blend the final primitive color with the
     59      * destination color. Defaults to kOne for src and kZero for dst (i.e. src mode).
     60      */
     61     void setBlendFunc(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
     62         fSrcBlendCoeff = srcCoeff;
     63         fDstBlendCoeff = dstCoeff;
     64     }
     65     GrBlendCoeff getSrcBlendCoeff() const { return fSrcBlendCoeff; }
     66     GrBlendCoeff getDstBlendCoeff() const { return fDstBlendCoeff; }
     67 
     68     /**
     69      * The initial color of the drawn primitive. Defaults to solid white.
     70      */
     71     void setColor(GrColor color) { fColor = color; }
     72     GrColor getColor() const { return fColor; }
     73 
     74     /**
     75      * Applies fractional coverage to the entire drawn primitive. Defaults to 0xff.
     76      */
     77     void setCoverage(uint8_t coverage) { fCoverage = coverage; }
     78     uint8_t getCoverage() const { return fCoverage; }
     79 
     80     /**
     81      * Should primitives be anti-aliased or not. Defaults to false.
     82      */
     83     void setAntiAlias(bool aa) { fAntiAlias = aa; }
     84     bool isAntiAlias() const { return fAntiAlias; }
     85 
     86     /**
     87      * Should dithering be applied. Defaults to false.
     88      */
     89     void setDither(bool dither) { fDither = dither; }
     90     bool isDither() const { return fDither; }
     91 
     92     /**
     93      * Enables a SkXfermode::Mode-based color filter applied to the primitive color. The constant
     94      * color passed to this function is considered the "src" color and the primitive's color is
     95      * considered the "dst" color. Defaults to kDst_Mode which equates to simply passing through
     96      * the primitive color unmodified.
     97      */
     98     void setXfermodeColorFilter(SkXfermode::Mode mode, GrColor color) {
     99         fColorFilterColor = color;
    100         fColorFilterXfermode = mode;
    101     }
    102     SkXfermode::Mode getColorFilterMode() const { return fColorFilterXfermode; }
    103     GrColor getColorFilterColor() const { return fColorFilterColor; }
    104 
    105     /**
    106      * Disables the SkXfermode::Mode color filter.
    107      */
    108     void resetColorFilter() {
    109         fColorFilterXfermode = SkXfermode::kDst_Mode;
    110         fColorFilterColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
    111     }
    112 
    113     /**
    114      * Specifies a stage of the color pipeline. Usually the texture matrices of color stages apply
    115      * to the primitive's positions. Some GrContext calls take explicit coords as an array or a
    116      * rect. In this case these are the pre-matrix coords to colorStage(0).
    117      */
    118     GrEffectStage* colorStage(int i) {
    119         GrAssert((unsigned)i < kMaxColorStages);
    120         return fColorStages + i;
    121     }
    122 
    123     const GrEffectStage& getColorStage(int i) const {
    124         GrAssert((unsigned)i < kMaxColorStages);
    125         return fColorStages[i];
    126     }
    127 
    128     bool isColorStageEnabled(int i) const {
    129         GrAssert((unsigned)i < kMaxColorStages);
    130         return (NULL != fColorStages[i].getEffect());
    131     }
    132 
    133     /**
    134      * Specifies a stage of the coverage pipeline. Coverage stages' texture matrices are always
    135      * applied to the primitive's position, never to explicit texture coords.
    136      */
    137     GrEffectStage* coverageStage(int i) {
    138         GrAssert((unsigned)i < kMaxCoverageStages);
    139         return fCoverageStages + i;
    140     }
    141 
    142     const GrEffectStage& getCoverageStage(int i) const {
    143         GrAssert((unsigned)i < kMaxCoverageStages);
    144         return fCoverageStages[i];
    145     }
    146 
    147     bool isCoverageStageEnabled(int i) const {
    148         GrAssert((unsigned)i < kMaxCoverageStages);
    149         return (NULL != fCoverageStages[i].getEffect());
    150     }
    151 
    152     bool hasCoverageStage() const {
    153         for (int i = 0; i < kMaxCoverageStages; ++i) {
    154             if (this->isCoverageStageEnabled(i)) {
    155                 return true;
    156             }
    157         }
    158         return false;
    159     }
    160 
    161     bool hasColorStage() const {
    162         for (int i = 0; i < kMaxColorStages; ++i) {
    163             if (this->isColorStageEnabled(i)) {
    164                 return true;
    165             }
    166         }
    167         return false;
    168     }
    169 
    170     bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
    171 
    172     /**
    173      * Called when the source coord system is changing. preConcatInverse is the inverse of the
    174      * transformation from the old coord system to the new coord system. Returns false if the matrix
    175      * cannot be inverted.
    176      */
    177     bool sourceCoordChangeByInverse(const SkMatrix& preConcatInverse) {
    178         SkMatrix inv;
    179         bool computed = false;
    180         for (int i = 0; i < kMaxColorStages; ++i) {
    181             if (this->isColorStageEnabled(i)) {
    182                 if (!computed && !preConcatInverse.invert(&inv)) {
    183                     return false;
    184                 } else {
    185                     computed = true;
    186                 }
    187                 fColorStages[i].preConcatCoordChange(inv);
    188             }
    189         }
    190         for (int i = 0; i < kMaxCoverageStages; ++i) {
    191             if (this->isCoverageStageEnabled(i)) {
    192                 if (!computed && !preConcatInverse.invert(&inv)) {
    193                     return false;
    194                 } else {
    195                     computed = true;
    196                 }
    197                 fCoverageStages[i].preConcatCoordChange(inv);
    198             }
    199         }
    200         return true;
    201     }
    202 
    203     /**
    204      * Called when the source coord system is changing. preConcat gives the transformation from the
    205      * old coord system to the new coord system.
    206      */
    207     void sourceCoordChange(const SkMatrix& preConcat) {
    208         for (int i = 0; i < kMaxColorStages; ++i) {
    209             if (this->isColorStageEnabled(i)) {
    210                 fColorStages[i].preConcatCoordChange(preConcat);
    211             }
    212         }
    213         for (int i = 0; i < kMaxCoverageStages; ++i) {
    214             if (this->isCoverageStageEnabled(i)) {
    215                 fCoverageStages[i].preConcatCoordChange(preConcat);
    216             }
    217         }
    218     }
    219 
    220     GrPaint& operator=(const GrPaint& paint) {
    221         fSrcBlendCoeff = paint.fSrcBlendCoeff;
    222         fDstBlendCoeff = paint.fDstBlendCoeff;
    223         fAntiAlias = paint.fAntiAlias;
    224         fDither = paint.fDither;
    225 
    226         fColor = paint.fColor;
    227         fCoverage = paint.fCoverage;
    228 
    229         fColorFilterColor = paint.fColorFilterColor;
    230         fColorFilterXfermode = paint.fColorFilterXfermode;
    231 
    232         for (int i = 0; i < kMaxColorStages; ++i) {
    233             if (paint.isColorStageEnabled(i)) {
    234                 fColorStages[i] = paint.fColorStages[i];
    235             }
    236         }
    237         for (int i = 0; i < kMaxCoverageStages; ++i) {
    238             if (paint.isCoverageStageEnabled(i)) {
    239                 fCoverageStages[i] = paint.fCoverageStages[i];
    240             }
    241         }
    242         return *this;
    243     }
    244 
    245     /**
    246      * Resets the paint to the defaults.
    247      */
    248     void reset() {
    249         this->resetBlend();
    250         this->resetOptions();
    251         this->resetColor();
    252         this->resetCoverage();
    253         this->resetStages();
    254         this->resetColorFilter();
    255     }
    256 
    257     // internal use
    258     // GrPaint's textures and masks map to the first N stages
    259     // of GrDrawTarget in that order (textures followed by masks)
    260     enum {
    261         kFirstColorStage = 0,
    262         kFirstCoverageStage = kMaxColorStages,
    263         kTotalStages = kFirstColorStage + kMaxColorStages + kMaxCoverageStages,
    264     };
    265 
    266 private:
    267 
    268     GrEffectStage               fColorStages[kMaxColorStages];
    269     GrEffectStage               fCoverageStages[kMaxCoverageStages];
    270 
    271     GrBlendCoeff                fSrcBlendCoeff;
    272     GrBlendCoeff                fDstBlendCoeff;
    273     bool                        fAntiAlias;
    274     bool                        fDither;
    275 
    276     GrColor                     fColor;
    277     uint8_t                     fCoverage;
    278 
    279     GrColor                     fColorFilterColor;
    280     SkXfermode::Mode            fColorFilterXfermode;
    281 
    282     void resetBlend() {
    283         fSrcBlendCoeff = kOne_GrBlendCoeff;
    284         fDstBlendCoeff = kZero_GrBlendCoeff;
    285     }
    286 
    287     void resetOptions() {
    288         fAntiAlias = false;
    289         fDither = false;
    290     }
    291 
    292     void resetColor() {
    293         fColor = GrColorPackRGBA(0xff, 0xff, 0xff, 0xff);
    294     }
    295 
    296     void resetCoverage() {
    297         fCoverage = 0xff;
    298     }
    299 
    300     void resetStages() {
    301         for (int i = 0; i < kMaxColorStages; ++i) {
    302             fColorStages[i].reset();
    303         }
    304         for (int i = 0; i < kMaxCoverageStages; ++i) {
    305             fCoverageStages[i].reset();
    306         }
    307     }
    308 };
    309 
    310 #endif
    311