1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <renderstate/Blend.h>
17 #include "Program.h"
18 
19 #include "ShadowTessellator.h"
20 
21 namespace android {
22 namespace uirenderer {
23 
24 /**
25  * Structure mapping Skia xfermodes to OpenGL blending factors.
26  */
27 struct Blender {
28     SkXfermode::Mode mode;
29     GLenum src;
30     GLenum dst;
31 };
32 
33 // In this array, the index of each Blender equals the value of the first
34 // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
35 const Blender kBlends[] = {
36     { SkXfermode::kClear_Mode,    GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
37     { SkXfermode::kSrc_Mode,      GL_ONE,                 GL_ZERO },
38     { SkXfermode::kDst_Mode,      GL_ZERO,                GL_ONE },
39     { SkXfermode::kSrcOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
40     { SkXfermode::kDstOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
41     { SkXfermode::kSrcIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
42     { SkXfermode::kDstIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
43     { SkXfermode::kSrcOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
44     { SkXfermode::kDstOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
45     { SkXfermode::kSrcATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
46     { SkXfermode::kDstATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
47     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
48     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
49     { SkXfermode::kModulate_Mode, GL_ZERO,                GL_SRC_COLOR },
50     { SkXfermode::kScreen_Mode,   GL_ONE,                 GL_ONE_MINUS_SRC_COLOR }
51 };
52 
53 // This array contains the swapped version of each SkXfermode. For instance
54 // this array's SrcOver blending mode is actually DstOver. You can refer to
55 // createLayer() for more information on the purpose of this array.
56 const Blender kBlendsSwap[] = {
57     { SkXfermode::kClear_Mode,    GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
58     { SkXfermode::kSrc_Mode,      GL_ZERO,                GL_ONE },
59     { SkXfermode::kDst_Mode,      GL_ONE,                 GL_ZERO },
60     { SkXfermode::kSrcOver_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_ONE },
61     { SkXfermode::kDstOver_Mode,  GL_ONE,                 GL_ONE_MINUS_SRC_ALPHA },
62     { SkXfermode::kSrcIn_Mode,    GL_ZERO,                GL_SRC_ALPHA },
63     { SkXfermode::kDstIn_Mode,    GL_DST_ALPHA,           GL_ZERO },
64     { SkXfermode::kSrcOut_Mode,   GL_ZERO,                GL_ONE_MINUS_SRC_ALPHA },
65     { SkXfermode::kDstOut_Mode,   GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
66     { SkXfermode::kSrcATop_Mode,  GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
67     { SkXfermode::kDstATop_Mode,  GL_DST_ALPHA,           GL_ONE_MINUS_SRC_ALPHA },
68     { SkXfermode::kXor_Mode,      GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
69     { SkXfermode::kPlus_Mode,     GL_ONE,                 GL_ONE },
70     { SkXfermode::kModulate_Mode, GL_DST_COLOR,           GL_ZERO },
71     { SkXfermode::kScreen_Mode,   GL_ONE_MINUS_DST_COLOR, GL_ONE }
72 };
73 
Blend()74 Blend::Blend()
75     : mEnabled(false)
76     , mSrcMode(GL_ZERO)
77     , mDstMode(GL_ZERO) {
78     // gl blending off by default
79 }
80 
enable(SkXfermode::Mode mode,ModeOrderSwap modeUsage)81 void Blend::enable(SkXfermode::Mode mode, ModeOrderSwap modeUsage) {
82     GLenum srcMode;
83     GLenum dstMode;
84     getFactors(mode, modeUsage, &srcMode, &dstMode);
85     setFactors(srcMode, dstMode);
86 }
87 
disable()88 void Blend::disable() {
89     if (mEnabled) {
90         glDisable(GL_BLEND);
91         mEnabled = false;
92     }
93 }
94 
invalidate()95 void Blend::invalidate() {
96     syncEnabled();
97     mSrcMode = mDstMode = GL_ZERO;
98 }
99 
syncEnabled()100 void Blend::syncEnabled() {
101     if (mEnabled) {
102         glEnable(GL_BLEND);
103     } else {
104         glDisable(GL_BLEND);
105     }
106 }
107 
getFactors(SkXfermode::Mode mode,ModeOrderSwap modeUsage,GLenum * outSrc,GLenum * outDst)108 void Blend::getFactors(SkXfermode::Mode mode, ModeOrderSwap modeUsage, GLenum* outSrc, GLenum* outDst) {
109     *outSrc = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].src : kBlends[mode].src;
110     *outDst = (modeUsage == ModeOrderSwap::Swap) ? kBlendsSwap[mode].dst : kBlends[mode].dst;
111 }
112 
setFactors(GLenum srcMode,GLenum dstMode)113 void Blend::setFactors(GLenum srcMode, GLenum dstMode) {
114     if (srcMode == GL_ZERO && dstMode == GL_ZERO) {
115         disable();
116     } else {
117         if (!mEnabled) {
118             glEnable(GL_BLEND);
119             mEnabled = true;
120         }
121 
122         if (srcMode != mSrcMode || dstMode != mDstMode) {
123             glBlendFunc(srcMode, dstMode);
124             mSrcMode = srcMode;
125             mDstMode = dstMode;
126         }
127     }
128 }
129 
dump()130 void Blend::dump() {
131     ALOGD("Blend: enabled %d, func src %d, dst %d", mEnabled, mSrcMode, mDstMode);
132 }
133 
134 } /* namespace uirenderer */
135 } /* namespace android */
136 
137