1 /* 2 * Copyright 2017 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 SkShaderBase_DEFINED 9 #define SkShaderBase_DEFINED 10 11 #include "SkFilterQuality.h" 12 #include "SkMatrix.h" 13 #include "SkShader.h" 14 15 class GrContext; 16 class GrFragmentProcessor; 17 class SkArenaAlloc; 18 class SkColorSpace; 19 class SkColorSpaceXformer; 20 class SkImage; 21 struct SkImageInfo; 22 class SkPaint; 23 class SkRasterPipeline; 24 25 class SkShaderBase : public SkShader { 26 public: 27 ~SkShaderBase() override; 28 29 /** 30 * Returns true if the shader is guaranteed to produce only a single color. 31 * Subclasses can override this to allow loop-hoisting optimization. 32 */ 33 virtual bool isConstant() const { return false; } 34 35 const SkMatrix& getLocalMatrix() const { return fLocalMatrix; } 36 37 enum Flags { 38 //!< set if all of the colors will be opaque 39 kOpaqueAlpha_Flag = 1 << 0, 40 41 /** set if the spans only vary in X (const in Y). 42 e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient 43 that varies from left-to-right. This flag specifies this for 44 shadeSpan(). 45 */ 46 kConstInY32_Flag = 1 << 1, 47 48 /** hint for the blitter that 4f is the preferred shading mode. 49 */ 50 kPrefers4f_Flag = 1 << 2, 51 }; 52 53 /** 54 * ContextRec acts as a parameter bundle for creating Contexts. 55 */ 56 struct ContextRec { 57 enum DstType { 58 kPMColor_DstType, // clients prefer shading into PMColor dest 59 kPM4f_DstType, // clients prefer shading into PM4f dest 60 }; 61 62 ContextRec(const SkPaint& paint, const SkMatrix& matrix, const SkMatrix* localM, 63 DstType dstType, SkColorSpace* dstColorSpace) 64 : fPaint(&paint) 65 , fMatrix(&matrix) 66 , fLocalMatrix(localM) 67 , fPreferredDstType(dstType) 68 , fDstColorSpace(dstColorSpace) {} 69 70 const SkPaint* fPaint; // the current paint associated with the draw 71 const SkMatrix* fMatrix; // the current matrix in the canvas 72 const SkMatrix* fLocalMatrix; // optional local matrix 73 const DstType fPreferredDstType; // the "natural" client dest type 74 SkColorSpace* fDstColorSpace; // the color space of the dest surface (if any) 75 }; 76 77 class Context : public ::SkNoncopyable { 78 public: 79 Context(const SkShaderBase& shader, const ContextRec&); 80 81 virtual ~Context(); 82 83 /** 84 * Called sometimes before drawing with this shader. Return the type of 85 * alpha your shader will return. The default implementation returns 0. 86 * Your subclass should override if it can (even sometimes) report a 87 * non-zero value, since that will enable various blitters to perform 88 * faster. 89 */ 90 virtual uint32_t getFlags() const { return 0; } 91 92 /** 93 * Called for each span of the object being drawn. Your subclass should 94 * set the appropriate colors (with premultiplied alpha) that correspond 95 * to the specified device coordinates. 96 */ 97 virtual void shadeSpan(int x, int y, SkPMColor[], int count) = 0; 98 99 virtual void shadeSpan4f(int x, int y, SkPM4f[], int count); 100 101 /** 102 * The const void* ctx is only const because all the implementations are const. 103 * This can be changed to non-const if a new shade proc needs to change the ctx. 104 */ 105 typedef void (*ShadeProc)(const void* ctx, int x, int y, SkPMColor[], int count); 106 virtual ShadeProc asAShadeProc(void** ctx); 107 108 /** 109 * Similar to shadeSpan, but only returns the alpha-channel for a span. 110 * The default implementation calls shadeSpan() and then extracts the alpha 111 * values from the returned colors. 112 */ 113 virtual void shadeSpanAlpha(int x, int y, uint8_t alpha[], int count); 114 115 // Notification from blitter::blitMask in case we need to see the non-alpha channels 116 virtual void set3DMask(const SkMask*) {} 117 118 protected: 119 // Reference to shader, so we don't have to dupe information. 120 const SkShaderBase& fShader; 121 122 uint8_t getPaintAlpha() const { return fPaintAlpha; } 123 const SkMatrix& getTotalInverse() const { return fTotalInverse; } 124 const SkMatrix& getCTM() const { return fCTM; } 125 126 private: 127 SkMatrix fCTM; 128 SkMatrix fTotalInverse; 129 uint8_t fPaintAlpha; 130 131 typedef SkNoncopyable INHERITED; 132 }; 133 134 /** 135 * Make a context using the memory provided by the arena. 136 * 137 * @return pointer to context or nullptr if can't be created 138 */ 139 Context* makeContext(const ContextRec&, SkArenaAlloc*) const; 140 141 /** 142 * Shaders may opt-in for burst mode, if they can operate 143 * significantly more efficiently in that mode. 144 * 145 * Burst mode is prioritized in SkRasterPipelineBlitter over 146 * regular (appendStages) pipeline operation. 147 */ 148 Context* makeBurstPipelineContext(const ContextRec&, SkArenaAlloc*) const; 149 150 #if SK_SUPPORT_GPU 151 struct AsFPArgs { 152 AsFPArgs() {} 153 AsFPArgs(GrContext* context, 154 const SkMatrix* viewMatrix, 155 const SkMatrix* localMatrix, 156 SkFilterQuality filterQuality, 157 SkColorSpace* dstColorSpace) 158 : fContext(context) 159 , fViewMatrix(viewMatrix) 160 , fLocalMatrix(localMatrix) 161 , fFilterQuality(filterQuality) 162 , fDstColorSpace(dstColorSpace) {} 163 164 GrContext* fContext; 165 const SkMatrix* fViewMatrix; 166 const SkMatrix* fLocalMatrix; 167 SkFilterQuality fFilterQuality; 168 SkColorSpace* fDstColorSpace; 169 }; 170 171 /** 172 * Returns a GrFragmentProcessor that implements the shader for the GPU backend. NULL is 173 * returned if there is no GPU implementation. 174 * 175 * The GPU device does not call SkShader::createContext(), instead we pass the view matrix, 176 * local matrix, and filter quality directly. 177 * 178 * The GrContext may be used by the to create textures that are required by the returned 179 * processor. 180 * 181 * The returned GrFragmentProcessor should expect an unpremultiplied input color and 182 * produce a premultiplied output. 183 */ 184 virtual sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const; 185 #endif 186 187 /** 188 * If the shader can represent its "average" luminance in a single color, return true and 189 * if color is not NULL, return that color. If it cannot, return false and ignore the color 190 * parameter. 191 * 192 * Note: if this returns true, the returned color will always be opaque, as only the RGB 193 * components are used to compute luminance. 194 */ 195 bool asLuminanceColor(SkColor*) const; 196 197 /** 198 * Returns a shader transformed into a new color space via the |xformer|. 199 */ 200 sk_sp<SkShader> makeColorSpace(SkColorSpaceXformer* xformer) const { 201 return this->onMakeColorSpace(xformer); 202 } 203 204 bool isRasterPipelineOnly() const { 205 // We always use RP when perspective is present. 206 return fLocalMatrix.hasPerspective() || this->onIsRasterPipelineOnly(); 207 } 208 209 // If this returns false, then we draw nothing (do not fall back to shader context) 210 bool appendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*, 211 const SkMatrix& ctm, const SkPaint&, const SkMatrix* localM=nullptr) const; 212 213 bool computeTotalInverse(const SkMatrix& ctm, 214 const SkMatrix* outerLocalMatrix, 215 SkMatrix* totalInverse) const; 216 217 #ifdef SK_SUPPORT_LEGACY_SHADER_ISABITMAP 218 virtual bool onIsABitmap(SkBitmap*, SkMatrix*, TileMode[2]) const { 219 return false; 220 } 221 #endif 222 223 virtual SkImage* onIsAImage(SkMatrix*, TileMode[2]) const { 224 return nullptr; 225 } 226 227 SK_TO_STRING_VIRT() 228 229 SK_DEFINE_FLATTENABLE_TYPE(SkShaderBase) 230 SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP() 231 232 protected: 233 SkShaderBase(const SkMatrix* localMatrix = nullptr); 234 235 void flatten(SkWriteBuffer&) const override; 236 237 /** 238 * Specialize creating a SkShader context using the supplied allocator. 239 * @return pointer to context owned by the arena allocator. 240 */ 241 virtual Context* onMakeContext(const ContextRec&, SkArenaAlloc*) const { 242 return nullptr; 243 } 244 245 /** 246 * Overriden by shaders which prefer burst mode. 247 */ 248 virtual Context* onMakeBurstPipelineContext(const ContextRec&, SkArenaAlloc*) const { 249 return nullptr; 250 } 251 252 virtual bool onAsLuminanceColor(SkColor*) const { 253 return false; 254 } 255 256 virtual sk_sp<SkShader> onMakeColorSpace(SkColorSpaceXformer*) const { 257 return sk_ref_sp(const_cast<SkShaderBase*>(this)); 258 } 259 260 // Default impl creates shadercontext and calls that (not very efficient) 261 virtual bool onAppendStages(SkRasterPipeline*, SkColorSpace* dstCS, SkArenaAlloc*, 262 const SkMatrix&, const SkPaint&, const SkMatrix* localM) const; 263 264 virtual bool onIsRasterPipelineOnly() const { return false; } 265 266 private: 267 // This is essentially const, but not officially so it can be modified in constructors. 268 SkMatrix fLocalMatrix; 269 270 typedef SkShader INHERITED; 271 }; 272 273 inline SkShaderBase* as_SB(SkShader* shader) { 274 return static_cast<SkShaderBase*>(shader); 275 } 276 277 inline const SkShaderBase* as_SB(const SkShader* shader) { 278 return static_cast<const SkShaderBase*>(shader); 279 } 280 281 inline const SkShaderBase* as_SB(const sk_sp<SkShader>& shader) { 282 return static_cast<SkShaderBase*>(shader.get()); 283 } 284 285 #endif // SkShaderBase_DEFINED 286