Home | History | Annotate | Download | only in shaders
      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