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 "src/gpu/effects/GrBlendFragmentProcessor.h" 9 10#include "src/gpu/GrFragmentProcessor.h" 11#include "src/gpu/SkGr.h" 12#include "src/gpu/glsl/GrGLSLBlend.h" 13#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 14 15// Some of the CPU implementations of blend modes differ from the GPU enough that 16// we can't use the CPU implementation to implement constantOutputForConstantInput. 17static inline bool does_cpu_blend_impl_match_gpu(SkBlendMode mode) { 18 // The non-separable modes differ too much. So does SoftLight. ColorBurn differs too much on our 19 // test iOS device, but we just disable it across the board since it might differ on untested 20 // GPUs. 21 return mode <= SkBlendMode::kLastSeparableMode && mode != SkBlendMode::kSoftLight && 22 mode != SkBlendMode::kColorBurn; 23} 24 25////////////////////////////////////////////////////////////////////////////// 26 27class BlendFragmentProcessor : public GrFragmentProcessor { 28public: 29 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src, 30 std::unique_ptr<GrFragmentProcessor> dst, 31 SkBlendMode mode) { 32 return std::unique_ptr<GrFragmentProcessor>( 33 new BlendFragmentProcessor(std::move(src), std::move(dst), mode)); 34 } 35 36 const char* name() const override { return "Blend"; } 37 38 SkString getShaderDfxInfo() const override { 39 SkString format; 40 format.printf("ShaderDfx_Blend_%d", fMode); 41 return format; 42 } 43 44 std::unique_ptr<GrFragmentProcessor> clone() const override; 45 46private: 47 BlendFragmentProcessor(std::unique_ptr<GrFragmentProcessor> src, 48 std::unique_ptr<GrFragmentProcessor> dst, 49 SkBlendMode mode) 50 : INHERITED(kBlendFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode)) 51 , fMode(mode) { 52 this->setIsBlendFunction(); 53 this->registerChild(std::move(src)); 54 this->registerChild(std::move(dst)); 55 } 56 57 BlendFragmentProcessor(const BlendFragmentProcessor& that) 58 : INHERITED(that) 59 , fMode(that.fMode) {} 60 61#if GR_TEST_UTILS 62 SkString onDumpInfo() const override { 63 return SkStringPrintf("(fMode=%s)", SkBlendMode_Name(fMode)); 64 } 65#endif 66 67 static OptimizationFlags OptFlags(const GrFragmentProcessor* src, 68 const GrFragmentProcessor* dst, SkBlendMode mode) { 69 OptimizationFlags flags; 70 switch (mode) { 71 case SkBlendMode::kClear: 72 case SkBlendMode::kSrc: 73 case SkBlendMode::kDst: 74 SkDEBUGFAIL("Shouldn't have created a Blend FP as 'clear', 'src', or 'dst'."); 75 flags = kNone_OptimizationFlags; 76 break; 77 78 // Produces opaque if both src and dst are opaque. These also will modulate the child's 79 // output by either the input color or alpha. However, if the child is not compatible 80 // with the coverage as alpha then it may produce a color that is not valid premul. 81 case SkBlendMode::kSrcIn: 82 case SkBlendMode::kDstIn: 83 case SkBlendMode::kModulate: 84 if (src && dst) { 85 flags = ProcessorOptimizationFlags(src) & ProcessorOptimizationFlags(dst) & 86 kPreservesOpaqueInput_OptimizationFlag; 87 } else if (src) { 88 flags = ProcessorOptimizationFlags(src) & 89 ~kConstantOutputForConstantInput_OptimizationFlag; 90 } else if (dst) { 91 flags = ProcessorOptimizationFlags(dst) & 92 ~kConstantOutputForConstantInput_OptimizationFlag; 93 } else { 94 flags = kNone_OptimizationFlags; 95 } 96 break; 97 98 // Produces zero when both are opaque, indeterminate if one is opaque. 99 case SkBlendMode::kSrcOut: 100 case SkBlendMode::kDstOut: 101 case SkBlendMode::kXor: 102 flags = kNone_OptimizationFlags; 103 break; 104 105 // Is opaque if the dst is opaque. 106 case SkBlendMode::kSrcATop: 107 flags = ProcessorOptimizationFlags(dst) & kPreservesOpaqueInput_OptimizationFlag; 108 break; 109 110 // DstATop is the converse of kSrcATop. Screen is also opaque if the src is a opaque. 111 case SkBlendMode::kDstATop: 112 case SkBlendMode::kScreen: 113 flags = ProcessorOptimizationFlags(src) & kPreservesOpaqueInput_OptimizationFlag; 114 break; 115 116 // These modes are all opaque if either src or dst is opaque. All the advanced modes 117 // compute alpha as src-over. 118 case SkBlendMode::kSrcOver: 119 case SkBlendMode::kDstOver: 120 case SkBlendMode::kPlus: 121 case SkBlendMode::kOverlay: 122 case SkBlendMode::kDarken: 123 case SkBlendMode::kLighten: 124 case SkBlendMode::kColorDodge: 125 case SkBlendMode::kColorBurn: 126 case SkBlendMode::kHardLight: 127 case SkBlendMode::kSoftLight: 128 case SkBlendMode::kDifference: 129 case SkBlendMode::kExclusion: 130 case SkBlendMode::kMultiply: 131 case SkBlendMode::kHue: 132 case SkBlendMode::kSaturation: 133 case SkBlendMode::kColor: 134 case SkBlendMode::kLuminosity: 135 flags = (ProcessorOptimizationFlags(src) | ProcessorOptimizationFlags(dst)) & 136 kPreservesOpaqueInput_OptimizationFlag; 137 break; 138 } 139 if (does_cpu_blend_impl_match_gpu(mode) && 140 (!src || src->hasConstantOutputForConstantInput()) && 141 (!dst || dst->hasConstantOutputForConstantInput())) { 142 flags |= kConstantOutputForConstantInput_OptimizationFlag; 143 } 144 return flags; 145 } 146 147 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { 148 b->add32((int)fMode); 149 } 150 151 bool onIsEqual(const GrFragmentProcessor& other) const override { 152 const BlendFragmentProcessor& cs = other.cast<BlendFragmentProcessor>(); 153 return fMode == cs.fMode; 154 } 155 156 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { 157 const auto* src = this->childProcessor(0); 158 const auto* dst = this->childProcessor(1); 159 160 SkPMColor4f srcColor = ConstantOutputForConstantInput(src, input); 161 SkPMColor4f dstColor = ConstantOutputForConstantInput(dst, input); 162 163 return SkBlendMode_Apply(fMode, srcColor, dstColor); 164 } 165 166 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override; 167 168 SkBlendMode fMode; 169 170 GR_DECLARE_FRAGMENT_PROCESSOR_TEST 171 172 using INHERITED = GrFragmentProcessor; 173}; 174 175///////////////////////////////////////////////////////////////////// 176 177 178GR_DEFINE_FRAGMENT_PROCESSOR_TEST(BlendFragmentProcessor); 179 180#if GR_TEST_UTILS 181std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::TestCreate(GrProcessorTestData* d) { 182 // Create one or two random fragment processors. 183 std::unique_ptr<GrFragmentProcessor> src(GrProcessorUnitTest::MakeOptionalChildFP(d)); 184 std::unique_ptr<GrFragmentProcessor> dst(GrProcessorUnitTest::MakeChildFP(d)); 185 if (d->fRandom->nextBool()) { 186 std::swap(src, dst); 187 } 188 189 SkBlendMode mode; 190 do { 191 mode = static_cast<SkBlendMode>(d->fRandom->nextRangeU(0, (int)SkBlendMode::kLastMode)); 192 } while (SkBlendMode::kClear == mode || SkBlendMode::kSrc == mode || SkBlendMode::kDst == mode); 193 return std::unique_ptr<GrFragmentProcessor>( 194 new BlendFragmentProcessor(std::move(src), std::move(dst), mode)); 195} 196#endif 197 198std::unique_ptr<GrFragmentProcessor> BlendFragmentProcessor::clone() const { 199 return std::unique_ptr<GrFragmentProcessor>(new BlendFragmentProcessor(*this)); 200} 201 202std::unique_ptr<GrFragmentProcessor::ProgramImpl> BlendFragmentProcessor::onMakeProgramImpl() const { 203 class Impl : public ProgramImpl { 204 public: 205 void emitCode(EmitArgs& args) override { 206 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 207 const BlendFragmentProcessor& bfp = args.fFp.cast<BlendFragmentProcessor>(); 208 SkBlendMode mode = bfp.fMode; 209 210 fragBuilder->codeAppendf("// Blend mode: %s\n", SkBlendMode_Name(mode)); 211 212 // Invoke src/dst with our input color (or substitute input color if no child FP) 213 SkString srcColor = this->invokeChild(0, args); 214 SkString dstColor = this->invokeChild(1, args); 215 216 // Blend src and dst colors together. 217 fragBuilder->codeAppendf("return %s(%s, %s);", 218 GrGLSLBlend::BlendFuncName(mode), 219 srcColor.c_str(), 220 dstColor.c_str()); 221 } 222 }; 223 224 return std::make_unique<Impl>(); 225} 226 227////////////////////////////////////////////////////////////////////////////// 228 229std::unique_ptr<GrFragmentProcessor> GrBlendFragmentProcessor::Make( 230 std::unique_ptr<GrFragmentProcessor> src, 231 std::unique_ptr<GrFragmentProcessor> dst, 232 SkBlendMode mode) { 233 switch (mode) { 234 case SkBlendMode::kClear: 235 return GrFragmentProcessor::MakeColor(SK_PMColor4fTRANSPARENT); 236 case SkBlendMode::kSrc: 237 return src; 238 case SkBlendMode::kDst: 239 return dst; 240 default: 241 return BlendFragmentProcessor::Make(std::move(src), std::move(dst), mode); 242 } 243} 244