aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrBlend.cpp
blob: c8631c42ef0d26c269d93705dbb2f909b57c6f11 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "GrBlend.h"

static inline GrBlendCoeff swap_coeff_src_dst(GrBlendCoeff coeff) {
    switch (coeff) {
        case kDC_GrBlendCoeff:
            return kSC_GrBlendCoeff;
        case kIDC_GrBlendCoeff:
            return kISC_GrBlendCoeff;
        case kDA_GrBlendCoeff:
            return kSA_GrBlendCoeff;
        case kIDA_GrBlendCoeff:
            return kISA_GrBlendCoeff;
        case kSC_GrBlendCoeff:
            return kDC_GrBlendCoeff;
        case kISC_GrBlendCoeff:
            return kIDC_GrBlendCoeff;
        case kSA_GrBlendCoeff:
            return kDA_GrBlendCoeff;
        case kISA_GrBlendCoeff:
            return kIDA_GrBlendCoeff;
        default:
            return coeff;
    }
}

static inline unsigned saturated_add(unsigned a, unsigned b) {
    SkASSERT(a <= 255);
    SkASSERT(b <= 255);
    unsigned sum = a + b;
    if (sum > 255) {
        sum = 255;
    }
    return sum;
}

static GrColor add_colors(GrColor src, GrColor dst) {
    unsigned r = saturated_add(GrColorUnpackR(src), GrColorUnpackR(dst));
    unsigned g = saturated_add(GrColorUnpackG(src), GrColorUnpackG(dst));
    unsigned b = saturated_add(GrColorUnpackB(src), GrColorUnpackB(dst));
    unsigned a = saturated_add(GrColorUnpackA(src), GrColorUnpackA(dst));
    return GrColorPackRGBA(r, g, b, a);
}

static inline bool valid_color(uint32_t compFlags) {
     return (kRGBA_GrColorComponentFlags & compFlags) == kRGBA_GrColorComponentFlags;
}

static GrColor simplify_blend_term(GrBlendCoeff* srcCoeff,
                                   GrColor srcColor, uint32_t srcCompFlags,
                                   GrColor dstColor, uint32_t dstCompFlags,
                                   GrColor constantColor) {

    SkASSERT(!GrBlendCoeffRefsSrc(*srcCoeff));
    SkASSERT(NULL != srcCoeff);

    // Check whether srcCoeff can be reduced to kOne or kZero based on known color inputs.
    // We could pick out the coeff r,g,b,a values here and use them to compute the blend term color,
    // if possible, below but that is not implemented now.
    switch (*srcCoeff) {
        case kIDC_GrBlendCoeff:
            dstColor = ~dstColor; // fallthrough
        case kDC_GrBlendCoeff:
            if (valid_color(dstCompFlags)) {
                if (0xffffffff == dstColor) {
                    *srcCoeff = kOne_GrBlendCoeff;
                } else if (0 == dstColor) {
                    *srcCoeff = kZero_GrBlendCoeff;
                }
            }
            break;

        case kIDA_GrBlendCoeff:
            dstColor = ~dstColor; // fallthrough
        case kDA_GrBlendCoeff:
            if (kA_GrColorComponentFlag & dstCompFlags) {
                if (0xff == GrColorUnpackA(dstColor)) {
                    *srcCoeff = kOne_GrBlendCoeff;
                } else if (0 == GrColorUnpackA(dstColor)) {
                    *srcCoeff = kZero_GrBlendCoeff;
                }
            }
            break;

        case kIConstC_GrBlendCoeff:
            constantColor = ~constantColor; // fallthrough
        case kConstC_GrBlendCoeff:
            if (0xffffffff == constantColor) {
                *srcCoeff = kOne_GrBlendCoeff;
            } else if (0 == constantColor) {
                *srcCoeff = kZero_GrBlendCoeff;
            }
            break;

        case kIConstA_GrBlendCoeff:
            constantColor = ~constantColor; // fallthrough
        case kConstA_GrBlendCoeff:
            if (0xff == GrColorUnpackA(constantColor)) {
                *srcCoeff = kOne_GrBlendCoeff;
            } else if (0 == GrColorUnpackA(constantColor)) {
                *srcCoeff = kZero_GrBlendCoeff;
            }
            break;

        default:
            break;
    }
    // We may have invalidated these above and shouldn't read them again.
    SkDEBUGCODE(dstColor = constantColor = GrColor_ILLEGAL;)

    if (kZero_GrBlendCoeff == *srcCoeff || (valid_color(srcCompFlags) && 0 == srcColor)) {
        *srcCoeff = kZero_GrBlendCoeff;
        return 0;
    }

    if (kOne_GrBlendCoeff == *srcCoeff && valid_color(srcCompFlags)) {
        return srcColor;
    } else {
        return GrColor_ILLEGAL;
    }
}

GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff,
                        GrBlendCoeff* dstCoeff,
                        GrColor srcColor, uint32_t srcCompFlags,
                        GrColor dstColor, uint32_t dstCompFlags,
                        GrColor constantColor) {
    GrColor srcTermColor = simplify_blend_term(srcCoeff,
                                               srcColor, srcCompFlags,
                                               dstColor, dstCompFlags,
                                               constantColor);

    // We call the same function to simplify the dst blend coeff. We trick it out by swapping the
    // src and dst.
    GrBlendCoeff spoofedCoeff = swap_coeff_src_dst(*dstCoeff);
    GrColor dstTermColor = simplify_blend_term(&spoofedCoeff,
                                               dstColor, dstCompFlags,
                                               srcColor, srcCompFlags,
                                               constantColor);
    *dstCoeff = swap_coeff_src_dst(spoofedCoeff);

    if (GrColor_ILLEGAL != srcTermColor && GrColor_ILLEGAL != dstTermColor) {
        return add_colors(srcTermColor, dstTermColor);
    } else {
        return GrColor_ILLEGAL;
    }
}