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 "GrTexture.h" 15 #include "GrTypes.h" 16 #include "SkXfermode.h" 17 18 class GrShaderCaps; 19 class GrGLSLCaps; 20 class GrGLSLXferProcessor; 21 class GrProcOptInfo; 22 struct GrPipelineOptimizations; 23 24 /** 25 * Barriers for blending. When a shader reads the dst directly, an Xfer barrier is sometimes 26 * required after a pixel has been written, before it can be safely read again. 27 */ 28 enum GrXferBarrierType { 29 kNone_GrXferBarrierType = 0, //<! No barrier is required 30 kTexture_GrXferBarrierType, //<! Required when a shader reads and renders to the same texture. 31 kBlend_GrXferBarrierType, //<! Required by certain blend extensions. 32 }; 33 /** Should be able to treat kNone as false in boolean expressions */ 34 GR_STATIC_ASSERT(SkToBool(kNone_GrXferBarrierType) == false); 35 36 /** 37 * GrXferProcessor is responsible for implementing the xfer mode that blends the src color and dst 38 * color, and for applying any coverage. It does this by emitting fragment shader code and 39 * controlling the fixed-function blend state. When dual-source blending is available, it may also 40 * write a seconday fragment shader output color. GrXferProcessor has two modes of operation: 41 * 42 * Dst read: When allowed by the backend API, or when supplied a texture of the destination, the 43 * GrXferProcessor may read the destination color. While operating in this mode, the subclass only 44 * provides shader code that blends the src and dst colors, and the base class applies coverage. 45 * 46 * No dst read: When not performing a dst read, the subclass is given full control of the fixed- 47 * function blend state and/or secondary output, and is responsible to apply coverage on its own. 48 * 49 * A GrXferProcessor is never installed directly into our draw state, but instead is created from a 50 * GrXPFactory once we have finalized the state of our draw. 51 */ 52 class GrXferProcessor : public GrProcessor { 53 public: 54 /** 55 * A texture that contains the dst pixel values and an integer coord offset from device space 56 * to the space of the texture. Depending on GPU capabilities a DstTexture may be used by a 57 * GrXferProcessor for blending in the fragment shader. 58 */ 59 class DstTexture { 60 public: DstTexture()61 DstTexture() { fOffset.set(0, 0); } 62 DstTexture(const DstTexture & other)63 DstTexture(const DstTexture& other) { 64 *this = other; 65 } 66 DstTexture(GrTexture * texture,const SkIPoint & offset)67 DstTexture(GrTexture* texture, const SkIPoint& offset) 68 : fTexture(SkSafeRef(texture)) 69 , fOffset(offset) { 70 } 71 72 DstTexture& operator=(const DstTexture& other) { 73 fTexture.reset(SkSafeRef(other.fTexture.get())); 74 fOffset = other.fOffset; 75 return *this; 76 } 77 offset()78 const SkIPoint& offset() const { return fOffset; } 79 setOffset(const SkIPoint & offset)80 void setOffset(const SkIPoint& offset) { fOffset = offset; } setOffset(int ox,int oy)81 void setOffset(int ox, int oy) { fOffset.set(ox, oy); } 82 texture()83 GrTexture* texture() const { return fTexture.get(); } 84 setTexture(GrTexture * texture)85 GrTexture* setTexture(GrTexture* texture) { 86 fTexture.reset(SkSafeRef(texture)); 87 return texture; 88 } 89 90 private: 91 SkAutoTUnref<GrTexture> fTexture; 92 SkIPoint fOffset; 93 }; 94 95 /** 96 * Sets a unique key on the GrProcessorKeyBuilder calls onGetGLSLProcessorKey(...) to get the 97 * specific subclass's key. 98 */ 99 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const; 100 101 /** Returns a new instance of the appropriate *GL* implementation class 102 for the given GrXferProcessor; caller is responsible for deleting 103 the object. */ 104 virtual GrGLSLXferProcessor* createGLSLInstance() const = 0; 105 106 /** 107 * Optimizations for blending / coverage that an OptDrawState should apply to itself. 108 */ 109 enum OptFlags { 110 /** 111 * The draw can be skipped completely. 112 */ 113 kSkipDraw_OptFlag = 0x1, 114 /** 115 * GrXferProcessor will ignore color, thus no need to provide 116 */ 117 kIgnoreColor_OptFlag = 0x2, 118 /** 119 * GrXferProcessor will ignore coverage, thus no need to provide 120 */ 121 kIgnoreCoverage_OptFlag = 0x4, 122 /** 123 * Clear color stages and override input color to that returned by getOptimizations 124 */ 125 kOverrideColor_OptFlag = 0x8, 126 /** 127 * Can tweak alpha for coverage. Currently this flag should only be used by a batch 128 */ 129 kCanTweakAlphaForCoverage_OptFlag = 0x20, 130 }; 131 132 static const OptFlags kNone_OptFlags = (OptFlags)0; 133 134 GR_DECL_BITFIELD_OPS_FRIENDS(OptFlags); 135 136 /** 137 * Determines which optimizations (as described by the ptFlags above) can be performed by 138 * the draw with this xfer processor. If this function is called, the xfer processor may change 139 * its state to reflected the given blend optimizations. If the XP needs to see a specific input 140 * color to blend correctly, it will set the OverrideColor flag and the output parameter 141 * overrideColor will be the required value that should be passed into the XP. 142 * A caller who calls this function on a XP is required to honor the returned OptFlags 143 * and color values for its draw. 144 */ 145 OptFlags getOptimizations(const GrPipelineOptimizations& optimizations, 146 bool doesStencilWrite, 147 GrColor* overrideColor, 148 const GrCaps& caps) const; 149 150 /** 151 * Returns whether this XP will require an Xfer barrier on the given rt. If true, outBarrierType 152 * is updated to contain the type of barrier needed. 153 */ 154 GrXferBarrierType xferBarrierType(const GrRenderTarget* rt, const GrCaps& caps) const; 155 156 struct BlendInfo { resetBlendInfo157 void reset() { 158 fEquation = kAdd_GrBlendEquation; 159 fSrcBlend = kOne_GrBlendCoeff; 160 fDstBlend = kZero_GrBlendCoeff; 161 fBlendConstant = 0; 162 fWriteColor = true; 163 } 164 165 SkDEBUGCODE(SkString dump() const;) 166 167 GrBlendEquation fEquation; 168 GrBlendCoeff fSrcBlend; 169 GrBlendCoeff fDstBlend; 170 GrColor fBlendConstant; 171 bool fWriteColor; 172 }; 173 174 void getBlendInfo(BlendInfo* blendInfo) const; 175 willReadDstColor()176 bool willReadDstColor() const { return fWillReadDstColor; } 177 178 /** 179 * Returns the texture to be used as the destination when reading the dst in the fragment 180 * shader. If the returned texture is NULL then the XP is either not reading the dst or we have 181 * extentions that support framebuffer fetching and thus don't need a copy of the dst texture. 182 */ getDstTexture()183 const GrTexture* getDstTexture() const { return fDstTexture.getTexture(); } 184 185 /** 186 * Returns the offset in device coords to use when accessing the dst texture to get the dst 187 * pixel color in the shader. This value is only valid if getDstTexture() != NULL. 188 */ dstTextureOffset()189 const SkIPoint& dstTextureOffset() const { 190 SkASSERT(this->getDstTexture()); 191 return fDstTextureOffset; 192 } 193 194 /** 195 * If we are performing a dst read, returns whether the base class will use mixed samples to 196 * antialias the shader's final output. If not doing a dst read, the subclass is responsible 197 * for antialiasing and this returns false. 198 */ dstReadUsesMixedSamples()199 bool dstReadUsesMixedSamples() const { return fDstReadUsesMixedSamples; } 200 201 /** 202 * Returns whether or not this xferProcossor will set a secondary output to be used with dual 203 * source blending. 204 */ 205 bool hasSecondaryOutput() const; 206 207 /** Returns true if this and other processor conservatively draw identically. It can only return 208 true when the two processor are of the same subclass (i.e. they return the same object from 209 from getFactory()). 210 211 A return value of true from isEqual() should not be used to test whether the processor would 212 generate the same shader code. To test for identical code generation use getGLSLProcessorKey 213 */ 214 isEqual(const GrXferProcessor & that)215 bool isEqual(const GrXferProcessor& that) const { 216 if (this->classID() != that.classID()) { 217 return false; 218 } 219 if (this->fWillReadDstColor != that.fWillReadDstColor) { 220 return false; 221 } 222 if (this->fDstTexture.getTexture() != that.fDstTexture.getTexture()) { 223 return false; 224 } 225 if (this->fDstTextureOffset != that.fDstTextureOffset) { 226 return false; 227 } 228 if (this->fDstReadUsesMixedSamples != that.fDstReadUsesMixedSamples) { 229 return false; 230 } 231 return this->onIsEqual(that); 232 } 233 234 protected: 235 GrXferProcessor(); 236 GrXferProcessor(const DstTexture*, bool willReadDstColor, bool hasMixedSamples); 237 238 private: notifyRefCntIsZero()239 void notifyRefCntIsZero() const final {} 240 241 virtual OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations, 242 bool doesStencilWrite, 243 GrColor* overrideColor, 244 const GrCaps& caps) const = 0; 245 246 /** 247 * Sets a unique key on the GrProcessorKeyBuilder that is directly associated with this xfer 248 * processor's GL backend implementation. 249 */ 250 virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps, 251 GrProcessorKeyBuilder* b) const = 0; 252 253 /** 254 * Determines the type of barrier (if any) required by the subclass. Note that the possibility 255 * that a kTexture type barrier is required is handled by the base class and need not be 256 * considered by subclass overrides of this function. 257 */ onXferBarrier(const GrRenderTarget *,const GrCaps &)258 virtual GrXferBarrierType onXferBarrier(const GrRenderTarget*, const GrCaps&) const { 259 return kNone_GrXferBarrierType; 260 } 261 262 /** 263 * If we are not performing a dst read, returns whether the subclass will set a secondary 264 * output. When using dst reads, the base class controls the secondary output and this method 265 * will not be called. 266 */ onHasSecondaryOutput()267 virtual bool onHasSecondaryOutput() const { return false; } 268 269 /** 270 * If we are not performing a dst read, retrieves the fixed-function blend state required by the 271 * subclass. When using dst reads, the base class controls the fixed-function blend state and 272 * this method will not be called. The BlendInfo struct comes initialized to "no blending". 273 */ onGetBlendInfo(BlendInfo *)274 virtual void onGetBlendInfo(BlendInfo*) const {} 275 276 virtual bool onIsEqual(const GrXferProcessor&) const = 0; 277 278 bool fWillReadDstColor; 279 bool fDstReadUsesMixedSamples; 280 SkIPoint fDstTextureOffset; 281 GrTextureAccess fDstTexture; 282 283 typedef GrFragmentProcessor INHERITED; 284 }; 285 286 GR_MAKE_BITFIELD_OPS(GrXferProcessor::OptFlags); 287 288 /////////////////////////////////////////////////////////////////////////////// 289 290 /** 291 * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is 292 * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the 293 * draw opaque, etc.). Once the state of the draw is finalized, we use the XPF along with all the 294 * draw information to create a GrXferProcessor (XP) which can implement the desired blending for 295 * the draw. 296 * 297 * Before the XP is created, the XPF is able to answer queries about what functionality the XPs it 298 * creates will have. For example, can it create an XP that supports RGB coverage or will the XP 299 * blend with the destination color. 300 */ 301 class GrXPFactory : public SkRefCnt { 302 public: 303 typedef GrXferProcessor::DstTexture DstTexture; 304 GrXferProcessor* createXferProcessor(const GrPipelineOptimizations& optimizations, 305 bool hasMixedSamples, 306 const DstTexture*, 307 const GrCaps& caps) const; 308 /** 309 * Known color information after blending, but before accounting for any coverage. 310 */ 311 struct InvariantBlendedColor { 312 bool fWillBlendWithDst; 313 GrColor fKnownColor; 314 GrColorComponentFlags fKnownColorFlags; 315 }; 316 317 /** 318 * Returns information about the output color, produced by XPs from this factory, that will be 319 * known after blending. Note that we can conflate coverage and color, so the actual values 320 * written to pixels with partial coverage may not always seem consistent with the invariant 321 * information returned by this function. 322 */ 323 virtual void getInvariantBlendedColor(const GrProcOptInfo& colorPOI, 324 InvariantBlendedColor*) const = 0; 325 326 bool willNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations, 327 bool hasMixedSamples) const; 328 isEqual(const GrXPFactory & that)329 bool isEqual(const GrXPFactory& that) const { 330 if (this->classID() != that.classID()) { 331 return false; 332 } 333 return this->onIsEqual(that); 334 } 335 336 /** 337 * Helper for down-casting to a GrXPFactory subclass 338 */ cast()339 template <typename T> const T& cast() const { return *static_cast<const T*>(this); } 340 classID()341 uint32_t classID() const { SkASSERT(kIllegalXPFClassID != fClassID); return fClassID; } 342 343 protected: GrXPFactory()344 GrXPFactory() : fClassID(kIllegalXPFClassID) {} 345 initClassID()346 template <typename XPF_SUBCLASS> void initClassID() { 347 static uint32_t kClassID = GenClassID(); 348 fClassID = kClassID; 349 } 350 351 uint32_t fClassID; 352 353 private: 354 virtual GrXferProcessor* onCreateXferProcessor(const GrCaps& caps, 355 const GrPipelineOptimizations& optimizations, 356 bool hasMixedSamples, 357 const DstTexture*) const = 0; 358 359 virtual bool onIsEqual(const GrXPFactory&) const = 0; 360 361 bool willReadDstColor(const GrCaps& caps, 362 const GrPipelineOptimizations& optimizations, 363 bool hasMixedSamples) const; 364 /** 365 * Returns true if the XP generated by this factory will explicitly read dst in the fragment 366 * shader. 367 */ 368 virtual bool onWillReadDstColor(const GrCaps& caps, 369 const GrPipelineOptimizations& optimizations, 370 bool hasMixedSamples) const = 0; 371 GenClassID()372 static uint32_t GenClassID() { 373 // fCurrXPFactoryID has been initialized to kIllegalXPFactoryID. The 374 // atomic inc returns the old value not the incremented value. So we add 375 // 1 to the returned value. 376 uint32_t id = static_cast<uint32_t>(sk_atomic_inc(&gCurrXPFClassID)) + 1; 377 if (!id) { 378 SkFAIL("This should never wrap as it should only be called once for each GrXPFactory " 379 "subclass."); 380 } 381 return id; 382 } 383 384 enum { 385 kIllegalXPFClassID = 0, 386 }; 387 static int32_t gCurrXPFClassID; 388 389 typedef GrProgramElement INHERITED; 390 }; 391 392 #endif 393 394