1 /* 2 * Copyright 2014 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 #ifndef GrXferProcessor_DEFINED 9 #define GrXferProcessor_DEFINED 10 11 #include "GrBlend.h" 12 #include "GrColor.h" 13 #include "GrProcessor.h" 14 #include "GrProcessorSet.h" 15 #include "GrTexture.h" 16 #include "GrTypes.h" 17 18 class GrShaderCaps; 19 class GrGLSLXferProcessor; 20 21 /** 22 * Barriers for blending. When a shader reads the dst directly, an Xfer barrier is sometimes 23 * required after a pixel has been written, before it can be safely read again. 24 */ 25 enum GrXferBarrierType { 26 kNone_GrXferBarrierType = 0, //<! No barrier is required 27 kTexture_GrXferBarrierType, //<! Required when a shader reads and renders to the same texture. 28 kBlend_GrXferBarrierType, //<! Required by certain blend extensions. 29 }; 30 /** Should be able to treat kNone as false in boolean expressions */ 31 GR_STATIC_ASSERT(SkToBool(kNone_GrXferBarrierType) == false); 32 33 /** 34 * GrXferProcessor is responsible for implementing the xfer mode that blends the src color and dst 35 * color, and for applying any coverage. It does this by emitting fragment shader code and 36 * controlling the fixed-function blend state. When dual-source blending is available, it may also 37 * write a seconday fragment shader output color. GrXferProcessor has two modes of operation: 38 * 39 * Dst read: When allowed by the backend API, or when supplied a texture of the destination, the 40 * GrXferProcessor may read the destination color. While operating in this mode, the subclass only 41 * provides shader code that blends the src and dst colors, and the base class applies coverage. 42 * 43 * No dst read: When not performing a dst read, the subclass is given full control of the fixed- 44 * function blend state and/or secondary output, and is responsible to apply coverage on its own. 45 * 46 * A GrXferProcessor is never installed directly into our draw state, but instead is created from a 47 * GrXPFactory once we have finalized the state of our draw. 48 */ 49 class GrXferProcessor : public GrProcessor { 50 public: 51 using FragmentProcessorAnalysis = GrProcessorSet::FragmentProcessorAnalysis; 52 53 /** 54 * A texture that contains the dst pixel values and an integer coord offset from device space 55 * to the space of the texture. Depending on GPU capabilities a DstTexture may be used by a 56 * GrXferProcessor for blending in the fragment shader. 57 */ 58 class DstTexture { 59 public: DstTexture()60 DstTexture() { fOffset.set(0, 0); } 61 DstTexture(const DstTexture & other)62 DstTexture(const DstTexture& other) { 63 *this = other; 64 } 65 DstTexture(GrTexture * texture,const SkIPoint & offset)66 DstTexture(GrTexture* texture, const SkIPoint& offset) 67 : fTexture(SkSafeRef(texture)), fOffset(texture ? offset : SkIPoint{0, 0}) {} 68 69 DstTexture& operator=(const DstTexture& other) { 70 fTexture = other.fTexture; 71 fOffset = other.fOffset; 72 return *this; 73 } 74 75 bool operator==(const DstTexture& that) const { 76 return fTexture == that.fTexture && fOffset == that.fOffset; 77 } 78 bool operator!=(const DstTexture& that) const { return !(*this == that); } 79 offset()80 const SkIPoint& offset() const { return fOffset; } 81 setOffset(const SkIPoint & offset)82 void setOffset(const SkIPoint& offset) { fOffset = offset; } setOffset(int ox,int oy)83 void setOffset(int ox, int oy) { fOffset.set(ox, oy); } 84 texture()85 GrTexture* texture() const { return fTexture.get(); } 86 setTexture(sk_sp<GrTexture> texture)87 void setTexture(sk_sp<GrTexture> texture) { 88 fTexture = std::move(texture); 89 if (!fTexture) { 90 fOffset = {0, 0}; 91 } 92 } 93 94 private: 95 sk_sp<GrTexture> fTexture; 96 SkIPoint fOffset; 97 }; 98 99 /** 100 * Sets a unique key on the GrProcessorKeyBuilder calls onGetGLSLProcessorKey(...) to get the 101 * specific subclass's key. 102 */ 103 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const; 104 105 /** Returns a new instance of the appropriate *GL* implementation class 106 for the given GrXferProcessor; caller is responsible for deleting 107 the object. */ 108 virtual GrGLSLXferProcessor* createGLSLInstance() const = 0; 109 110 /** 111 * Optimizations for blending / coverage that an OptDrawState should apply to itself. 112 */ 113 enum OptFlags { 114 /** 115 * GrXferProcessor will ignore color, thus no need to provide 116 */ 117 kIgnoreColor_OptFlag = 0x1, 118 /** 119 * Can tweak alpha for coverage. 120 */ 121 kCanTweakAlphaForCoverage_OptFlag = 0x2, 122 }; 123 124 static const OptFlags kNone_OptFlags = (OptFlags)0; 125 126 GR_DECL_BITFIELD_OPS_FRIENDS(OptFlags); 127 128 /** 129 * Determines which optimizations (as described by the ptFlags above) can be performed by 130 * the draw with this xfer processor. If this function is called, the xfer processor may change 131 * its state to reflected the given blend optimizations. Callers are required to honor the 132 * returned OptFlags. 133 */ 134 OptFlags getOptimizations(const FragmentProcessorAnalysis&) const; 135 136 /** 137 * Returns whether this XP will require an Xfer barrier on the given rt. If true, outBarrierType 138 * is updated to contain the type of barrier needed. 139 */ 140 GrXferBarrierType xferBarrierType(const GrRenderTarget* rt, const GrCaps& caps) const; 141 142 struct BlendInfo { resetBlendInfo143 void reset() { 144 fEquation = kAdd_GrBlendEquation; 145 fSrcBlend = kOne_GrBlendCoeff; 146 fDstBlend = kZero_GrBlendCoeff; 147 fBlendConstant = 0; 148 fWriteColor = true; 149 } 150 151 SkDEBUGCODE(SkString dump() const;) 152 153 GrBlendEquation fEquation; 154 GrBlendCoeff fSrcBlend; 155 GrBlendCoeff fDstBlend; 156 GrColor fBlendConstant; 157 bool fWriteColor; 158 }; 159 160 void getBlendInfo(BlendInfo* blendInfo) const; 161 willReadDstColor()162 bool willReadDstColor() const { return fWillReadDstColor; } 163 164 /** 165 * Returns the texture to be used as the destination when reading the dst in the fragment 166 * shader. If the returned texture is NULL then the XP is either not reading the dst or we have 167 * extentions that support framebuffer fetching and thus don't need a copy of the dst texture. 168 */ getDstTexture()169 const GrTexture* getDstTexture() const { return fDstTexture.texture(); } 170 171 /** 172 * Returns the offset in device coords to use when accessing the dst texture to get the dst 173 * pixel color in the shader. This value is only valid if getDstTexture() != NULL. 174 */ dstTextureOffset()175 const SkIPoint& dstTextureOffset() const { 176 SkASSERT(this->getDstTexture()); 177 return fDstTextureOffset; 178 } 179 180 /** 181 * If we are performing a dst read, returns whether the base class will use mixed samples to 182 * antialias the shader's final output. If not doing a dst read, the subclass is responsible 183 * for antialiasing and this returns false. 184 */ dstReadUsesMixedSamples()185 bool dstReadUsesMixedSamples() const { return fDstReadUsesMixedSamples; } 186 187 /** 188 * Returns whether or not this xferProcossor will set a secondary output to be used with dual 189 * source blending. 190 */ 191 bool hasSecondaryOutput() const; 192 193 /** Returns true if this and other processor conservatively draw identically. It can only return 194 true when the two processor are of the same subclass (i.e. they return the same object from 195 from getFactory()). 196 197 A return value of true from isEqual() should not be used to test whether the processor would 198 generate the same shader code. To test for identical code generation use getGLSLProcessorKey 199 */ 200 isEqual(const GrXferProcessor & that)201 bool isEqual(const GrXferProcessor& that) const { 202 if (this->classID() != that.classID()) { 203 return false; 204 } 205 if (this->fWillReadDstColor != that.fWillReadDstColor) { 206 return false; 207 } 208 if (this->fDstTexture.texture() != that.fDstTexture.texture()) { 209 return false; 210 } 211 if (this->fDstTextureOffset != that.fDstTextureOffset) { 212 return false; 213 } 214 if (this->fDstReadUsesMixedSamples != that.fDstReadUsesMixedSamples) { 215 return false; 216 } 217 return this->onIsEqual(that); 218 } 219 220 protected: 221 GrXferProcessor(); 222 GrXferProcessor(const DstTexture*, bool willReadDstColor, bool hasMixedSamples); 223 224 private: notifyRefCntIsZero()225 void notifyRefCntIsZero() const final {} 226 227 virtual OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const = 0; 228 229 /** 230 * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer 231 * processor's GL backend implementation. 232 */ 233 virtual void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const = 0; 234 235 /** 236 * Determines the type of barrier (if any) required by the subclass. Note that the possibility 237 * that a kTexture type barrier is required is handled by the base class and need not be 238 * considered by subclass overrides of this function. 239 */ onXferBarrier(const GrRenderTarget *,const GrCaps &)240 virtual GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const { 241 return kNone_GrXferBarrierType; 242 } 243 244 /** 245 * If we are not performing a dst read, returns whether the subclass will set a secondary 246 * output. When using dst reads, the base class controls the secondary output and this method 247 * will not be called. 248 */ onHasSecondaryOutput()249 virtual bool onHasSecondaryOutput() const { return false; } 250 251 /** 252 * If we are not performing a dst read, retrieves the fixed-function blend state required by the 253 * subclass. When using dst reads, the base class controls the fixed-function blend state and 254 * this method will not be called. The BlendInfo struct comes initialized to "no blending". 255 */ onGetBlendInfo(BlendInfo *)256 virtual void onGetBlendInfo(BlendInfo*) const {} 257 258 virtual bool onIsEqual(const GrXferProcessor&) const = 0; 259 260 bool fWillReadDstColor; 261 bool fDstReadUsesMixedSamples; 262 SkIPoint fDstTextureOffset; 263 TextureSampler fDstTexture; 264 265 typedef GrFragmentProcessor INHERITED; 266 }; 267 268 GR_MAKE_BITFIELD_OPS(GrXferProcessor::OptFlags); 269 270 /////////////////////////////////////////////////////////////////////////////// 271 272 /** 273 * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is 274 * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the 275 * draw opaque, etc.). Once the state of the draw is finalized, we use the XPF along with all the 276 * draw information to create a GrXferProcessor (XP) which can implement the desired blending for 277 * the draw. 278 * 279 * Before the XP is created, the XPF is able to answer queries about what functionality the XPs it 280 * creates will have. For example, can it create an XP that supports RGB coverage or will the XP 281 * blend with the destination color. 282 * 283 * GrXPFactories are intended to be static immutable objects. We pass them around as raw pointers 284 * and expect the pointers to always be valid and for the factories to be reusable and thread safe. 285 * Equality is tested for using pointer comparison. GrXPFactory destructors must be no-ops. 286 */ 287 288 // In order to construct GrXPFactory subclass instances as constexpr the subclass, and therefore 289 // GrXPFactory, must be a literal type. One requirement is having a trivial destructor. This is ok 290 // since these objects have no need for destructors. However, GCC and clang throw a warning when a 291 // class has virtual functions and a non-virtual destructor. We suppress that warning here and 292 // for the subclasses. 293 #if defined(__GNUC__) || defined(__clang) 294 #pragma GCC diagnostic push 295 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 296 #endif 297 class GrXPFactory { 298 public: 299 using FragmentProcessorAnalysis = GrProcessorSet::FragmentProcessorAnalysis; 300 301 typedef GrXferProcessor::DstTexture DstTexture; 302 303 GrXferProcessor* createXferProcessor(const FragmentProcessorAnalysis&, 304 bool hasMixedSamples, 305 const DstTexture*, 306 const GrCaps& caps) const; 307 308 /** 309 * This will return true if the xfer processor needs the dst color in the shader and the way 310 * that the color will be made available to the xfer processor is by sampling a texture. 311 */ 312 static bool WillNeedDstTexture(const GrXPFactory*, 313 const GrCaps&, 314 const FragmentProcessorAnalysis&); 315 316 static bool CompatibleWithCoverageAsAlpha(const GrXPFactory*, bool colorIsOpaque); 317 318 /** 319 * This indicates whether the the xfer processor will produce the same bleneded color result 320 * if a series of overlapping stencil and cover operations are replaced by a series of stencil 321 * operations and a single cover. A uniform src color is assumed. 322 **/ 323 static bool CanCombineOverlappedStencilAndCover(const GrXPFactory*, bool colorIsOpaque); 324 325 protected: GrXPFactory()326 constexpr GrXPFactory() {} 327 328 private: 329 virtual GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, 330 const FragmentProcessorAnalysis&, 331 bool hasMixedSamples, 332 const DstTexture*) const = 0; 333 334 /** 335 * Returns true if the XP generated by this factory will explicitly read dst in the fragment 336 * shader. 337 */ 338 virtual bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const = 0; 339 340 virtual bool compatibleWithCoverageAsAlpha(bool colorIsOpaque) const = 0; canCombineOverlappedStencilAndCover(bool colorIsOpaque)341 virtual bool canCombineOverlappedStencilAndCover(bool colorIsOpaque) const { return false; } 342 }; 343 #if defined(__GNUC__) || defined(__clang) 344 #pragma GCC diagnostic pop 345 #endif 346 347 #endif 348 349