| 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 "include/core/SkRefCnt.h" |
| 12 | #include "include/gpu/GrTypes.h" |
| 13 | #include "include/private/base/SkAssert.h" |
| 14 | #include "include/private/base/SkTo.h" |
| 15 | #include "src/gpu/Blend.h" |
| 16 | #include "src/gpu/Swizzle.h" |
| 17 | #include "src/gpu/ganesh/GrCaps.h" |
| 18 | #include "src/gpu/ganesh/GrNonAtomicRef.h" |
| 19 | #include "src/gpu/ganesh/GrProcessor.h" |
| 20 | #include "src/gpu/ganesh/GrProcessorAnalysis.h" |
| 21 | #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h" |
| 22 | |
| 23 | #include <memory> |
| 24 | |
| 25 | class GrGLSLProgramDataManager; |
| 26 | class GrGLSLXPFragmentBuilder; |
| 27 | enum class GrClampType; |
| 28 | enum class SkBlendMode; |
| 29 | namespace skgpu { class KeyBuilder; } |
| 30 | struct GrShaderCaps; |
| 31 | |
| 32 | /** |
| 33 | * Barriers for blending. When a shader reads the dst directly, an Xfer barrier is sometimes |
| 34 | * required after a pixel has been written, before it can be safely read again. |
| 35 | */ |
| 36 | enum GrXferBarrierType { |
| 37 | kNone_GrXferBarrierType = 0, //<! No barrier is required |
| 38 | kTexture_GrXferBarrierType, //<! Required when a shader reads and renders to the same texture. |
| 39 | kBlend_GrXferBarrierType, //<! Required by certain blend extensions. |
| 40 | }; |
| 41 | /** Should be able to treat kNone as false in boolean expressions */ |
| 42 | static_assert(SkToBool(x: kNone_GrXferBarrierType) == false); |
| 43 | |
| 44 | // Flag version of the above enum. |
| 45 | enum class GrXferBarrierFlags { |
| 46 | kNone = 0, |
| 47 | kTexture = 1 << 0, |
| 48 | kBlend = 1 << 1, |
| 49 | }; |
| 50 | |
| 51 | GR_MAKE_BITFIELD_CLASS_OPS(GrXferBarrierFlags) |
| 52 | |
| 53 | /** |
| 54 | * GrXferProcessor is responsible for implementing the xfer mode that blends the src color and dst |
| 55 | * color, and for applying any coverage. It does this by emitting fragment shader code and |
| 56 | * controlling the fixed-function blend state. When dual-source blending is available, it may also |
| 57 | * write a secondary fragment shader output color. GrXferProcessor has two modes of operation: |
| 58 | * |
| 59 | * Dst read: When allowed by the backend API, or when supplied a texture of the destination, the |
| 60 | * GrXferProcessor may read the destination color. While operating in this mode, the subclass only |
| 61 | * provides shader code that blends the src and dst colors, and the base class applies coverage. |
| 62 | * |
| 63 | * No dst read: When not performing a dst read, the subclass is given full control of the fixed- |
| 64 | * function blend state and/or secondary output, and is responsible to apply coverage on its own. |
| 65 | * |
| 66 | * A GrXferProcessor is never installed directly into our draw state, but instead is created from a |
| 67 | * GrXPFactory once we have finalized the state of our draw. |
| 68 | */ |
| 69 | class GrXferProcessor : public GrProcessor, public GrNonAtomicRef<GrXferProcessor> { |
| 70 | public: |
| 71 | /** |
| 72 | * Every GrXferProcessor must be capable of creating a subclass of ProgramImpl. The ProgramImpl |
| 73 | * emits the shader code combines determines the fragment shader output(s) from the color and |
| 74 | * coverage FP outputs, is attached to the generated backend API pipeline/program, and used to |
| 75 | * extract uniform data from GrXferProcessor instances. |
| 76 | */ |
| 77 | class ProgramImpl; |
| 78 | |
| 79 | /** |
| 80 | * Adds a key on the skgpu::KeyBuilder calls onAddToKey(...) to get the specific subclass's key. |
| 81 | */ |
| 82 | void addToKey(const GrShaderCaps&, |
| 83 | skgpu::KeyBuilder*, |
| 84 | const GrSurfaceOrigin* originIfDstTexture, |
| 85 | bool usesInputAttachmentForDstRead) const; |
| 86 | |
| 87 | /** Returns a new instance of the appropriate *GL* implementation class |
| 88 | for the given GrXferProcessor; caller is responsible for deleting |
| 89 | the object. */ |
| 90 | virtual std::unique_ptr<ProgramImpl> makeProgramImpl() const = 0; |
| 91 | |
| 92 | /** |
| 93 | * Returns the barrier type, if any, that this XP will require. Note that the possibility |
| 94 | * that a kTexture type barrier is required is handled by the GrPipeline and need not be |
| 95 | * considered by subclass overrides of this function. |
| 96 | */ |
| 97 | virtual GrXferBarrierType xferBarrierType(const GrCaps& caps) const { |
| 98 | return kNone_GrXferBarrierType; |
| 99 | } |
| 100 | |
| 101 | inline skgpu::BlendInfo getBlendInfo() const { |
| 102 | skgpu::BlendInfo blendInfo; |
| 103 | if (!this->willReadDstColor()) { |
| 104 | this->onGetBlendInfo(&blendInfo); |
| 105 | } |
| 106 | return blendInfo; |
| 107 | } |
| 108 | |
| 109 | bool willReadDstColor() const { return fWillReadDstColor; } |
| 110 | |
| 111 | /** |
| 112 | * Returns whether or not this xferProcossor will set a secondary output to be used with dual |
| 113 | * source blending. |
| 114 | */ |
| 115 | bool hasSecondaryOutput() const; |
| 116 | |
| 117 | bool isLCD() const { return fIsLCD; } |
| 118 | |
| 119 | /** Returns true if this and other processor conservatively draw identically. It can only return |
| 120 | true when the two processor are of the same subclass (i.e. they return the same object from |
| 121 | from getFactory()). |
| 122 | |
| 123 | A return value of true from isEqual() should not be used to test whether the processor would |
| 124 | generate the same shader code. To test for identical code generation use addToKey. |
| 125 | */ |
| 126 | |
| 127 | bool isEqual(const GrXferProcessor& that) const { |
| 128 | if (this->classID() != that.classID()) { |
| 129 | return false; |
| 130 | } |
| 131 | if (this->fWillReadDstColor != that.fWillReadDstColor) { |
| 132 | return false; |
| 133 | } |
| 134 | if (fIsLCD != that.fIsLCD) { |
| 135 | return false; |
| 136 | } |
| 137 | return this->onIsEqual(that); |
| 138 | } |
| 139 | |
| 140 | protected: |
| 141 | GrXferProcessor(ClassID classID); |
| 142 | GrXferProcessor(ClassID classID, bool willReadDstColor, GrProcessorAnalysisCoverage); |
| 143 | |
| 144 | private: |
| 145 | /** |
| 146 | * Adds a key on the skgpu::KeyBuilder that reflects any variety in the code that may be emitted |
| 147 | * by the xfer processor subclass. |
| 148 | */ |
| 149 | virtual void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const = 0; |
| 150 | |
| 151 | /** |
| 152 | * If we are not performing a dst read, returns whether the subclass will set a secondary |
| 153 | * output. When using dst reads, the base class controls the secondary output and this method |
| 154 | * will not be called. |
| 155 | */ |
| 156 | virtual bool onHasSecondaryOutput() const { return false; } |
| 157 | |
| 158 | /** |
| 159 | * If we are not performing a dst read, retrieves the fixed-function blend state required by the |
| 160 | * subclass. When using dst reads, the base class controls the fixed-function blend state and |
| 161 | * this method will not be called. The BlendInfo struct comes initialized to "no blending". |
| 162 | */ |
| 163 | virtual void onGetBlendInfo(skgpu::BlendInfo*) const {} |
| 164 | |
| 165 | virtual bool onIsEqual(const GrXferProcessor&) const = 0; |
| 166 | |
| 167 | bool fWillReadDstColor; |
| 168 | bool fIsLCD; |
| 169 | |
| 170 | using INHERITED = GrProcessor; |
| 171 | }; |
| 172 | |
| 173 | /** |
| 174 | * We install a GrXPFactory (XPF) early on in the pipeline before all the final draw information is |
| 175 | * known (e.g. whether there is fractional pixel coverage, will coverage be 1 or 4 channel, is the |
| 176 | * draw opaque, etc.). Once the state of the draw is finalized, we use the XPF along with all the |
| 177 | * draw information to create a GrXferProcessor (XP) which can implement the desired blending for |
| 178 | * the draw. |
| 179 | * |
| 180 | * Before the XP is created, the XPF is able to answer queries about what functionality the XPs it |
| 181 | * creates will have. For example, can it create an XP that supports RGB coverage or will the XP |
| 182 | * blend with the destination color. |
| 183 | * |
| 184 | * GrXPFactories are intended to be static immutable objects. We pass them around as raw pointers |
| 185 | * and expect the pointers to always be valid and for the factories to be reusable and thread safe. |
| 186 | * Equality is tested for using pointer comparison. GrXPFactory destructors must be no-ops. |
| 187 | */ |
| 188 | |
| 189 | // In order to construct GrXPFactory subclass instances as constexpr the subclass, and therefore |
| 190 | // GrXPFactory, must be a literal type. One requirement is having a trivial destructor. This is ok |
| 191 | // since these objects have no need for destructors. However, GCC and clang throw a warning when a |
| 192 | // class has virtual functions and a non-virtual destructor. We suppress that warning here and |
| 193 | // for the subclasses. |
| 194 | #if defined(__GNUC__) |
| 195 | #pragma GCC diagnostic push |
| 196 | #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" |
| 197 | #endif |
| 198 | #if defined(__clang__) |
| 199 | #pragma clang diagnostic push |
| 200 | #pragma clang diagnostic ignored "-Wnon-virtual-dtor" |
| 201 | #endif |
| 202 | class GrXPFactory { |
| 203 | public: |
| 204 | enum class AnalysisProperties : unsigned { |
| 205 | kNone = 0x0, |
| 206 | /** |
| 207 | * The fragment shader will require the destination color. |
| 208 | */ |
| 209 | kReadsDstInShader = 0x1, |
| 210 | /** |
| 211 | * The op may apply coverage as alpha and still blend correctly. |
| 212 | */ |
| 213 | kCompatibleWithCoverageAsAlpha = 0x2, |
| 214 | /** |
| 215 | * The color input to the GrXferProcessor will be ignored. |
| 216 | */ |
| 217 | kIgnoresInputColor = 0x4, |
| 218 | /** |
| 219 | * The destination color will be provided to the fragment processor using a texture. This is |
| 220 | * additional information about the implementation of kReadsDstInShader. |
| 221 | */ |
| 222 | kRequiresDstTexture = 0x10, |
| 223 | /** |
| 224 | * If set, each pixel can only be touched once during a draw (e.g., because we have a dst |
| 225 | * texture or because we need an xfer barrier). |
| 226 | */ |
| 227 | kRequiresNonOverlappingDraws = 0x20, |
| 228 | /** |
| 229 | * If set the draw will use fixed function non coherent advanced blends. |
| 230 | */ |
| 231 | kUsesNonCoherentHWBlending = 0x40, |
| 232 | /** |
| 233 | * If set, the existing dst value has no effect on the final output. |
| 234 | */ |
| 235 | kUnaffectedByDstValue = 0x80, |
| 236 | }; |
| 237 | GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(AnalysisProperties); |
| 238 | |
| 239 | static sk_sp<const GrXferProcessor> MakeXferProcessor(const GrXPFactory*, |
| 240 | const GrProcessorAnalysisColor&, |
| 241 | GrProcessorAnalysisCoverage, |
| 242 | const GrCaps& caps, |
| 243 | GrClampType); |
| 244 | |
| 245 | static AnalysisProperties GetAnalysisProperties(const GrXPFactory*, |
| 246 | const GrProcessorAnalysisColor&, |
| 247 | const GrProcessorAnalysisCoverage&, |
| 248 | const GrCaps&, |
| 249 | GrClampType); |
| 250 | |
| 251 | static const GrXPFactory* FromBlendMode(SkBlendMode); |
| 252 | |
| 253 | protected: |
| 254 | constexpr GrXPFactory() {} |
| 255 | |
| 256 | private: |
| 257 | virtual sk_sp<const GrXferProcessor> makeXferProcessor(const GrProcessorAnalysisColor&, |
| 258 | GrProcessorAnalysisCoverage, |
| 259 | const GrCaps&, |
| 260 | GrClampType) const = 0; |
| 261 | |
| 262 | /** |
| 263 | * Subclass analysis implementation. This should not return kNeedsDstInTexture as that will be |
| 264 | * inferred by the base class based on kReadsDstInShader and the caps. |
| 265 | */ |
| 266 | virtual AnalysisProperties analysisProperties(const GrProcessorAnalysisColor&, |
| 267 | const GrProcessorAnalysisCoverage&, |
| 268 | const GrCaps&, |
| 269 | GrClampType) const = 0; |
| 270 | }; |
| 271 | #if defined(__GNUC__) |
| 272 | #pragma GCC diagnostic pop |
| 273 | #endif |
| 274 | #if defined(__clang__) |
| 275 | #pragma clang diagnostic pop |
| 276 | #endif |
| 277 | |
| 278 | GR_MAKE_BITFIELD_CLASS_OPS(GrXPFactory::AnalysisProperties) |
| 279 | |
| 280 | ////////////////////////////////////////////////////////////////////////////// |
| 281 | |
| 282 | class GrXferProcessor::ProgramImpl { |
| 283 | public: |
| 284 | virtual ~ProgramImpl() = default; |
| 285 | |
| 286 | using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; |
| 287 | |
| 288 | struct EmitArgs { |
| 289 | EmitArgs(GrGLSLXPFragmentBuilder* fragBuilder, |
| 290 | GrGLSLUniformHandler* uniformHandler, |
| 291 | const GrShaderCaps* caps, |
| 292 | const GrXferProcessor& xp, |
| 293 | const char* inputColor, |
| 294 | const char* inputCoverage, |
| 295 | const char* outputPrimary, |
| 296 | const char* outputSecondary, |
| 297 | const SamplerHandle dstTextureSamplerHandle, |
| 298 | GrSurfaceOrigin dstTextureOrigin, |
| 299 | const skgpu::Swizzle& writeSwizzle) |
| 300 | : fXPFragBuilder(fragBuilder) |
| 301 | , fUniformHandler(uniformHandler) |
| 302 | , fShaderCaps(caps) |
| 303 | , fXP(xp) |
| 304 | , fInputColor(inputColor ? inputColor : "half4(1.0)" ) |
| 305 | , fInputCoverage(inputCoverage) |
| 306 | , fOutputPrimary(outputPrimary) |
| 307 | , fOutputSecondary(outputSecondary) |
| 308 | , fDstTextureSamplerHandle(dstTextureSamplerHandle) |
| 309 | , fDstTextureOrigin(dstTextureOrigin) |
| 310 | , fWriteSwizzle(writeSwizzle) {} |
| 311 | GrGLSLXPFragmentBuilder* fXPFragBuilder; |
| 312 | GrGLSLUniformHandler* fUniformHandler; |
| 313 | const GrShaderCaps* fShaderCaps; |
| 314 | const GrXferProcessor& fXP; |
| 315 | const char* fInputColor; |
| 316 | const char* fInputCoverage; |
| 317 | const char* fOutputPrimary; |
| 318 | const char* fOutputSecondary; |
| 319 | const SamplerHandle fDstTextureSamplerHandle; |
| 320 | GrSurfaceOrigin fDstTextureOrigin; |
| 321 | skgpu::Swizzle fWriteSwizzle; |
| 322 | }; |
| 323 | /** |
| 324 | * This is similar to emitCode() in the base class, except it takes a full shader builder. |
| 325 | * This allows the effect subclass to emit vertex code. |
| 326 | */ |
| 327 | void emitCode(const EmitArgs&); |
| 328 | |
| 329 | /** A ProgramImpl instance can be reused with any GrXferProcessor that produces the same key. |
| 330 | This function reads data from a GrXferProcessor and uploads any uniform variables required |
| 331 | by the shaders created in emitCode(). The GrXferProcessor parameter is guaranteed to be of |
| 332 | the same type that created this ProgramImpl and to have an identical processor key as the |
| 333 | one that created this ProgramImpl. This function calls onSetData on the subclass of |
| 334 | ProgramImpl. |
| 335 | */ |
| 336 | void setData(const GrGLSLProgramDataManager& pdm, const GrXferProcessor& xp); |
| 337 | |
| 338 | protected: |
| 339 | ProgramImpl() = default; |
| 340 | |
| 341 | static void DefaultCoverageModulation(GrGLSLXPFragmentBuilder* fragBuilder, |
| 342 | const char* srcCoverage, |
| 343 | const char* dstColor, |
| 344 | const char* outColor, |
| 345 | const char* outColorSecondary, |
| 346 | const GrXferProcessor& proc); |
| 347 | |
| 348 | private: |
| 349 | /** |
| 350 | * Called by emitCode() when the XP will not be performing a dst read. This method is |
| 351 | * responsible for both blending and coverage. A subclass only needs to implement this method if |
| 352 | * it can construct a GrXferProcessor that will not read the dst color. |
| 353 | */ |
| 354 | virtual void emitOutputsForBlendState(const EmitArgs&) { |
| 355 | SK_ABORT("emitOutputsForBlendState not implemented." ); |
| 356 | } |
| 357 | |
| 358 | /** |
| 359 | * Called by emitCode() when the XP will perform a dst read. This method only needs to supply |
| 360 | * the blending logic. The base class applies coverage. A subclass only needs to implement this |
| 361 | * method if it can construct a GrXferProcessor that reads the dst color. |
| 362 | */ |
| 363 | virtual void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder*, |
| 364 | GrGLSLUniformHandler*, |
| 365 | const char* srcColor, |
| 366 | const char* srcCoverage, |
| 367 | const char* dstColor, |
| 368 | const char* outColor, |
| 369 | const char* outColorSecondary, |
| 370 | const GrXferProcessor&) { |
| 371 | SK_ABORT("emitBlendCodeForDstRead not implemented." ); |
| 372 | } |
| 373 | |
| 374 | virtual void emitWriteSwizzle(GrGLSLXPFragmentBuilder*, |
| 375 | const skgpu::Swizzle&, |
| 376 | const char* outColor, |
| 377 | const char* outColorSecondary) const; |
| 378 | |
| 379 | virtual void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) {} |
| 380 | }; |
| 381 | |
| 382 | #endif |
| 383 | |