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 "GrPipelineBuilder.h"
11 #include "GrProcOptInfo.h"
12 #include "gl/GrGLCaps.h"
13 
GrXferProcessor()14 GrXferProcessor::GrXferProcessor()
15     : fWillReadDstColor(false)
16     , fDstReadUsesMixedSamples(false)
17     , fDstTextureOffset() {
18 }
19 
GrXferProcessor(const DstTexture * dstTexture,bool willReadDstColor,bool hasMixedSamples)20 GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture,
21                                  bool willReadDstColor,
22                                  bool hasMixedSamples)
23     : fWillReadDstColor(willReadDstColor)
24     , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples)
25     , fDstTextureOffset() {
26     if (dstTexture && dstTexture->texture()) {
27         SkASSERT(willReadDstColor);
28         fDstTexture.reset(dstTexture->texture());
29         fDstTextureOffset = dstTexture->offset();
30         this->addTextureAccess(&fDstTexture);
31         this->setWillReadFragmentPosition();
32     }
33 }
34 
getOptimizations(const GrPipelineOptimizations & optimizations,bool doesStencilWrite,GrColor * overrideColor,const GrCaps & caps) const35 GrXferProcessor::OptFlags GrXferProcessor::getOptimizations(
36                                                        const GrPipelineOptimizations& optimizations,
37                                                        bool doesStencilWrite,
38                                                        GrColor* overrideColor,
39                                                        const GrCaps& caps) const {
40     GrXferProcessor::OptFlags flags = this->onGetOptimizations(optimizations,
41                                                                doesStencilWrite,
42                                                                overrideColor,
43                                                                caps);
44 
45     if (this->willReadDstColor()) {
46         // When performing a dst read we handle coverage in the base class.
47         SkASSERT(!(flags & GrXferProcessor::kIgnoreCoverage_OptFlag));
48         if (optimizations.fCoveragePOI.isSolidWhite()) {
49             flags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
50         }
51     }
52     return flags;
53 }
54 
hasSecondaryOutput() const55 bool GrXferProcessor::hasSecondaryOutput() const {
56     if (!this->willReadDstColor()) {
57         return this->onHasSecondaryOutput();
58     }
59     return this->dstReadUsesMixedSamples();
60 }
61 
getBlendInfo(BlendInfo * blendInfo) const62 void GrXferProcessor::getBlendInfo(BlendInfo* blendInfo) const {
63     blendInfo->reset();
64     if (!this->willReadDstColor()) {
65         this->onGetBlendInfo(blendInfo);
66     } else if (this->dstReadUsesMixedSamples()) {
67         blendInfo->fDstBlend = kIS2A_GrBlendCoeff;
68     }
69 }
70 
getGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const71 void GrXferProcessor::getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
72     uint32_t key = this->willReadDstColor() ? 0x1 : 0x0;
73     if (key) {
74         if (const GrTexture* dstTexture = this->getDstTexture()) {
75             key |= 0x2;
76             if (kTopLeft_GrSurfaceOrigin == dstTexture->origin()) {
77                 key |= 0x4;
78             }
79         }
80         if (this->dstReadUsesMixedSamples()) {
81             key |= 0x8;
82         }
83     }
84     b->add32(key);
85     this->onGetGLSLProcessorKey(caps, b);
86 }
87 
xferBarrierType(const GrRenderTarget * rt,const GrCaps & caps) const88 GrXferBarrierType GrXferProcessor::xferBarrierType(const GrRenderTarget* rt,
89                                                    const GrCaps& caps) const {
90     SkASSERT(rt);
91     if (static_cast<const GrSurface*>(rt) == this->getDstTexture()) {
92         // Texture barriers are required when a shader reads and renders to the same texture.
93         SkASSERT(caps.textureBarrierSupport());
94         return kTexture_GrXferBarrierType;
95     }
96     return this->onXferBarrier(rt, caps);
97 }
98 
99 #ifdef SK_DEBUG
equation_string(GrBlendEquation eq)100 static const char* equation_string(GrBlendEquation eq) {
101     switch (eq) {
102         case kAdd_GrBlendEquation:
103             return "add";
104         case kSubtract_GrBlendEquation:
105             return "subtract";
106         case kReverseSubtract_GrBlendEquation:
107             return "reverse_subtract";
108         case kScreen_GrBlendEquation:
109             return "screen";
110         case kOverlay_GrBlendEquation:
111             return "overlay";
112         case kDarken_GrBlendEquation:
113             return "darken";
114         case kLighten_GrBlendEquation:
115             return "lighten";
116         case kColorDodge_GrBlendEquation:
117             return "color_dodge";
118         case kColorBurn_GrBlendEquation:
119             return "color_burn";
120         case kHardLight_GrBlendEquation:
121             return "hard_light";
122         case kSoftLight_GrBlendEquation:
123             return "soft_light";
124         case kDifference_GrBlendEquation:
125             return "difference";
126         case kExclusion_GrBlendEquation:
127             return "exclusion";
128         case kMultiply_GrBlendEquation:
129             return "multiply";
130         case kHSLHue_GrBlendEquation:
131             return "hsl_hue";
132         case kHSLSaturation_GrBlendEquation:
133             return "hsl_saturation";
134         case kHSLColor_GrBlendEquation:
135             return "hsl_color";
136         case kHSLLuminosity_GrBlendEquation:
137             return "hsl_luminosity";
138     };
139     return "";
140 }
141 
coeff_string(GrBlendCoeff coeff)142 static const char* coeff_string(GrBlendCoeff coeff) {
143     switch (coeff) {
144         case kZero_GrBlendCoeff:
145             return "zero";
146         case kOne_GrBlendCoeff:
147             return "one";
148         case kSC_GrBlendCoeff:
149             return "src_color";
150         case kISC_GrBlendCoeff:
151             return "inv_src_color";
152         case kDC_GrBlendCoeff:
153             return "dst_color";
154         case kIDC_GrBlendCoeff:
155             return "inv_dst_color";
156         case kSA_GrBlendCoeff:
157             return "src_alpha";
158         case kISA_GrBlendCoeff:
159             return "inv_src_alpha";
160         case kDA_GrBlendCoeff:
161             return "dst_alpha";
162         case kIDA_GrBlendCoeff:
163             return "inv_dst_alpha";
164         case kConstC_GrBlendCoeff:
165             return "const_color";
166         case kIConstC_GrBlendCoeff:
167             return "inv_const_color";
168         case kConstA_GrBlendCoeff:
169             return "const_alpha";
170         case kIConstA_GrBlendCoeff:
171             return "inv_const_alpha";
172         case kS2C_GrBlendCoeff:
173             return "src2_color";
174         case kIS2C_GrBlendCoeff:
175             return "inv_src2_color";
176         case kS2A_GrBlendCoeff:
177             return "src2_alpha";
178         case kIS2A_GrBlendCoeff:
179             return "inv_src2_alpha";
180     }
181     return "";
182 }
183 
dump() const184 SkString GrXferProcessor::BlendInfo::dump() const {
185     SkString out;
186     out.printf("write_color(%d) equation(%s) src_coeff(%s) dst_coeff:(%s) const(0x%08x)",
187                fWriteColor, equation_string(fEquation), coeff_string(fSrcBlend),
188                coeff_string(fDstBlend), fBlendConstant);
189     return out;
190 }
191 #endif
192 
193 ///////////////////////////////////////////////////////////////////////////////
194 
createXferProcessor(const GrPipelineOptimizations & optimizations,bool hasMixedSamples,const DstTexture * dstTexture,const GrCaps & caps) const195 GrXferProcessor* GrXPFactory::createXferProcessor(const GrPipelineOptimizations& optimizations,
196                                                   bool hasMixedSamples,
197                                                   const DstTexture* dstTexture,
198                                                   const GrCaps& caps) const {
199 #ifdef SK_DEBUG
200     if (this->willReadDstColor(caps, optimizations, hasMixedSamples)) {
201         if (!caps.shaderCaps()->dstReadInShaderSupport()) {
202             SkASSERT(dstTexture && dstTexture->texture());
203         } else {
204             SkASSERT(!dstTexture || !dstTexture->texture());
205         }
206     } else {
207         SkASSERT(!dstTexture || !dstTexture->texture());
208     }
209     SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport());
210 #endif
211     return this->onCreateXferProcessor(caps, optimizations, hasMixedSamples, dstTexture);
212 }
213 
willNeedDstTexture(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples) const214 bool GrXPFactory::willNeedDstTexture(const GrCaps& caps,
215                                      const GrPipelineOptimizations& optimizations,
216                                      bool hasMixedSamples) const {
217     return (this->willReadDstColor(caps, optimizations, hasMixedSamples) &&
218             !caps.shaderCaps()->dstReadInShaderSupport());
219 }
220 
willReadDstColor(const GrCaps & caps,const GrPipelineOptimizations & optimizations,bool hasMixedSamples) const221 bool GrXPFactory::willReadDstColor(const GrCaps& caps,
222                                    const GrPipelineOptimizations& optimizations,
223                                    bool hasMixedSamples) const {
224     return optimizations.fOverrides.fUsePLSDstRead || this->onWillReadDstColor(caps, optimizations,
225                                                                                hasMixedSamples);
226 }
227