1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "GrXferProcessor.h"
9 #include "GrPipeline.h"
10 #include "gl/GrGLCaps.h"
11 
GrXferProcessor()12 GrXferProcessor::GrXferProcessor()
13     : fWillReadDstColor(false)
14     , fDstReadUsesMixedSamples(false)
15     , fDstTextureOffset() {
16 }
17 
GrXferProcessor(const DstTexture * dstTexture,bool willReadDstColor,bool hasMixedSamples)18 GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture,
19                                  bool willReadDstColor,
20                                  bool hasMixedSamples)
21     : fWillReadDstColor(willReadDstColor)
22     , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples)
23     , fDstTextureOffset() {
24     if (dstTexture && dstTexture->texture()) {
25         SkASSERT(willReadDstColor);
26         fDstTexture.reset(dstTexture->texture());
27         fDstTextureOffset = dstTexture->offset();
28         this->addTextureSampler(&fDstTexture);
29     }
30 }
31 
getOptimizations(const FragmentProcessorAnalysis & analysis) const32 GrXferProcessor::OptFlags GrXferProcessor::getOptimizations(
33         const FragmentProcessorAnalysis& analysis) const {
34     return this->onGetOptimizations(analysis);
35 }
36 
hasSecondaryOutput() const37 bool GrXferProcessor::hasSecondaryOutput() const {
38     if (!this->willReadDstColor()) {
39         return this->onHasSecondaryOutput();
40     }
41     return this->dstReadUsesMixedSamples();
42 }
43 
getBlendInfo(BlendInfo * blendInfo) const44 void GrXferProcessor::getBlendInfo(BlendInfo* blendInfo) const {
45     blendInfo->reset();
46     if (!this->willReadDstColor()) {
47         this->onGetBlendInfo(blendInfo);
48     } else if (this->dstReadUsesMixedSamples()) {
49         blendInfo->fDstBlend = kIS2A_GrBlendCoeff;
50     }
51 }
52 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const53 void GrXferProcessor::getGLSLProcessorKey(const GrShaderCaps& caps,
54                                           GrProcessorKeyBuilder* b) const {
55     uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
56     if (key) {
57         if (const GrTexture* dstTexture = this->getDstTexture()) {
58             key |= 0x2;
59             if (kTopLeft_GrSurfaceOrigin == dstTexture->origin()) {
60                 key |= 0x4;
61             }
62         }
63         if (this->dstReadUsesMixedSamples()) {
64             key |= 0x8;
65         }
66     }
67     b->add32(key);
68     this->onGetGLSLProcessorKey(caps, b);
69 }
70 
xferBarrierType(const GrRenderTarget * rt,const GrCaps & caps) const71 GrXferBarrierType GrXferProcessor::xferBarrierType(const GrRenderTarget* rt,
72                                                    const GrCaps& caps) const {
73     SkASSERT(rt);
74     if (static_cast<const GrSurface*>(rt) == this->getDstTexture()) {
75         // Texture barriers are required when a shader reads and renders to the same texture.
76         SkASSERT(caps.textureBarrierSupport());
77         return kTexture_GrXferBarrierType;
78     }
79     return this->onXferBarrier(rt, caps);
80 }
81 
82 #ifdef SK_DEBUG
equation_string(GrBlendEquation eq)83 static const char* equation_string(GrBlendEquation eq) {
84     switch (eq) {
85         case kAdd_GrBlendEquation:
86             return "add";
87         case kSubtract_GrBlendEquation:
88             return "subtract";
89         case kReverseSubtract_GrBlendEquation:
90             return "reverse_subtract";
91         case kScreen_GrBlendEquation:
92             return "screen";
93         case kOverlay_GrBlendEquation:
94             return "overlay";
95         case kDarken_GrBlendEquation:
96             return "darken";
97         case kLighten_GrBlendEquation:
98             return "lighten";
99         case kColorDodge_GrBlendEquation:
100             return "color_dodge";
101         case kColorBurn_GrBlendEquation:
102             return "color_burn";
103         case kHardLight_GrBlendEquation:
104             return "hard_light";
105         case kSoftLight_GrBlendEquation:
106             return "soft_light";
107         case kDifference_GrBlendEquation:
108             return "difference";
109         case kExclusion_GrBlendEquation:
110             return "exclusion";
111         case kMultiply_GrBlendEquation:
112             return "multiply";
113         case kHSLHue_GrBlendEquation:
114             return "hsl_hue";
115         case kHSLSaturation_GrBlendEquation:
116             return "hsl_saturation";
117         case kHSLColor_GrBlendEquation:
118             return "hsl_color";
119         case kHSLLuminosity_GrBlendEquation:
120             return "hsl_luminosity";
121     };
122     return "";
123 }
124 
coeff_string(GrBlendCoeff coeff)125 static const char* coeff_string(GrBlendCoeff coeff) {
126     switch (coeff) {
127         case kZero_GrBlendCoeff:
128             return "zero";
129         case kOne_GrBlendCoeff:
130             return "one";
131         case kSC_GrBlendCoeff:
132             return "src_color";
133         case kISC_GrBlendCoeff:
134             return "inv_src_color";
135         case kDC_GrBlendCoeff:
136             return "dst_color";
137         case kIDC_GrBlendCoeff:
138             return "inv_dst_color";
139         case kSA_GrBlendCoeff:
140             return "src_alpha";
141         case kISA_GrBlendCoeff:
142             return "inv_src_alpha";
143         case kDA_GrBlendCoeff:
144             return "dst_alpha";
145         case kIDA_GrBlendCoeff:
146             return "inv_dst_alpha";
147         case kConstC_GrBlendCoeff:
148             return "const_color";
149         case kIConstC_GrBlendCoeff:
150             return "inv_const_color";
151         case kConstA_GrBlendCoeff:
152             return "const_alpha";
153         case kIConstA_GrBlendCoeff:
154             return "inv_const_alpha";
155         case kS2C_GrBlendCoeff:
156             return "src2_color";
157         case kIS2C_GrBlendCoeff:
158             return "inv_src2_color";
159         case kS2A_GrBlendCoeff:
160             return "src2_alpha";
161         case kIS2A_GrBlendCoeff:
162             return "inv_src2_alpha";
163     }
164     return "";
165 }
166 
dump() const167 SkString GrXferProcessor::BlendInfo::dump() const {
168     SkString out;
169     out.printf("write_color(%d) equation(%s) src_coeff(%s) dst_coeff:(%s) const(0x%08x)",
170                fWriteColor, equation_string(fEquation), coeff_string(fSrcBlend),
171                coeff_string(fDstBlend), fBlendConstant);
172     return out;
173 }
174 #endif
175 
176 ///////////////////////////////////////////////////////////////////////////////
177 
WillNeedDstTexture(const GrXPFactory * factory,const GrCaps & caps,const GrProcessorSet::FragmentProcessorAnalysis & analysis)178 bool GrXPFactory::WillNeedDstTexture(const GrXPFactory* factory, const GrCaps& caps,
179                                      const GrProcessorSet::FragmentProcessorAnalysis& analysis) {
180     bool result;
181     if (factory) {
182         result = !caps.shaderCaps()->dstReadInShaderSupport() &&
183                  factory->willReadDstInShader(caps, analysis);
184     } else {
185         result = GrPorterDuffXPFactory::WillSrcOverNeedDstTexture(caps, analysis);
186     }
187     return result;
188 }
189 
CompatibleWithCoverageAsAlpha(const GrXPFactory * factory,bool colorIsOpaque)190 bool GrXPFactory::CompatibleWithCoverageAsAlpha(const GrXPFactory* factory, bool colorIsOpaque) {
191     if (factory) {
192         return factory->compatibleWithCoverageAsAlpha(colorIsOpaque);
193     }
194     return GrPorterDuffXPFactory::SrcOverIsCompatibleWithCoverageAsAlpha();
195 }
196 
CanCombineOverlappedStencilAndCover(const GrXPFactory * factory,bool colorIsOpaque)197 bool GrXPFactory::CanCombineOverlappedStencilAndCover(const GrXPFactory* factory,
198                                                       bool colorIsOpaque) {
199     if (factory) {
200         return factory->canCombineOverlappedStencilAndCover(colorIsOpaque);
201     }
202     return GrPorterDuffXPFactory::SrcOverCanCombineOverlappedStencilAndCover(colorIsOpaque);
203 }
204 
createXferProcessor(const FragmentProcessorAnalysis & analysis,bool hasMixedSamples,const DstTexture * dstTexture,const GrCaps & caps) const205 GrXferProcessor* GrXPFactory::createXferProcessor(const FragmentProcessorAnalysis& analysis,
206                                                   bool hasMixedSamples,
207                                                   const DstTexture* dstTexture,
208                                                   const GrCaps& caps) const {
209 #ifdef SK_DEBUG
210     if (this->willReadDstInShader(caps, analysis)) {
211         if (!caps.shaderCaps()->dstReadInShaderSupport()) {
212             SkASSERT(dstTexture && dstTexture->texture());
213         } else {
214             SkASSERT(!dstTexture || !dstTexture->texture());
215         }
216     } else {
217         SkASSERT(!dstTexture || !dstTexture->texture());
218     }
219     SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport());
220 #endif
221     return this->onCreateXferProcessor(caps, analysis, hasMixedSamples, dstTexture);
222 }
223