Home | History | Annotate | Download | only in effects
      1 /*
      2  * Copyright 2018 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 GrSkSLFP_DEFINED
      9 #define GrSkSLFP_DEFINED
     10 
     11 #include "GrCaps.h"
     12 #include "GrFragmentProcessor.h"
     13 #include "GrCoordTransform.h"
     14 #include "GrShaderCaps.h"
     15 #include "SkSLCompiler.h"
     16 #include "SkSLPipelineStageCodeGenerator.h"
     17 #include "SkRefCnt.h"
     18 #include "../private/GrSkSLFPFactoryCache.h"
     19 #include <atomic>
     20 
     21 #if GR_TEST_UTILS
     22 #define GR_FP_SRC_STRING const char*
     23 #else
     24 #define GR_FP_SRC_STRING static const char*
     25 #endif
     26 
     27 class GrContext_Base;
     28 class GrSkSLFPFactory;
     29 
     30 class GrSkSLFP : public GrFragmentProcessor {
     31 public:
     32     /**
     33      * Returns a new unique identifier. Each different SkSL fragment processor should call
     34      * NewIndex once, statically, and use this index for all calls to Make.
     35      */
     36     static int NewIndex() {
     37         static std::atomic<int> nextIndex{0};
     38         return nextIndex++;
     39     }
     40 
     41     /**
     42      * Creates a new fragment processor from an SkSL source string and a struct of inputs to the
     43      * program. The input struct's type is derived from the 'in' variables in the SkSL source, so
     44      * e.g. the shader:
     45      *
     46      *    in bool dither;
     47      *    in float x;
     48      *    in float y;
     49      *    ....
     50      *
     51      * would expect a pointer to a struct set up like:
     52      *
     53      * struct {
     54      *     bool dither;
     55      *     float x;
     56      *     float y;
     57      * };
     58      *
     59      * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
     60      * based on the inputs, internally the process is divided into two steps: we first parse and
     61      * semantically analyze the SkSL into an internal representation, and then "specialize" this
     62      * internal representation based on the inputs. The unspecialized internal representation of
     63      * the program is cached, so further specializations of the same code are much faster than the
     64      * first call.
     65      *
     66      * This caching is based on the 'index' parameter, which should be derived by statically calling
     67      * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
     68      * associated with it.
     69      */
     70     static std::unique_ptr<GrSkSLFP> Make(
     71                    GrContext_Base* context,
     72                    int index,
     73                    const char* name,
     74                    const char* sksl,
     75                    const void* inputs,
     76                    size_t inputSize);
     77 
     78     static std::unique_ptr<GrSkSLFP> Make(
     79                    GrContext_Base* context,
     80                    int index,
     81                    const char* name,
     82                    SkString sksl,
     83                    const void* inputs,
     84                    size_t inputSize);
     85 
     86     const char* name() const override;
     87 
     88     void addChild(std::unique_ptr<GrFragmentProcessor> child);
     89 
     90     std::unique_ptr<GrFragmentProcessor> clone() const override;
     91 
     92 private:
     93     GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, int fIndex,
     94              const char* name, const char* sksl, SkString skslString, const void* inputs,
     95              size_t inputSize);
     96 
     97     GrSkSLFP(const GrSkSLFP& other);
     98 
     99     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
    100 
    101     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
    102 
    103     bool onIsEqual(const GrFragmentProcessor&) const override;
    104 
    105     void createFactory() const;
    106 
    107     sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
    108 
    109     const sk_sp<GrShaderCaps> fShaderCaps;
    110 
    111     mutable sk_sp<GrSkSLFPFactory> fFactory;
    112 
    113     int fIndex;
    114 
    115     const char* fName;
    116 
    117     // For object lifetime purposes, we have fields for the SkSL as both a const char* and a
    118     // SkString. The const char* is the one we actually use, but it may point to the SkString's
    119     // bytes. Since GrSkSLFPs are frequently created from constant strings, this allows us to
    120     // generally avoid the overhead of copying the bytes into an SkString (in which case fSkSLString
    121     // is the empty string), while still allowing the GrSkSLFP to manage the string's lifetime when
    122     // needed.
    123     SkString fSkSLString;
    124 
    125     const char* fSkSL;
    126 
    127     const std::unique_ptr<int8_t[]> fInputs;
    128 
    129     size_t fInputSize;
    130 
    131     mutable SkSL::String fKey;
    132 
    133     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
    134 
    135     typedef GrFragmentProcessor INHERITED;
    136 
    137     friend class GrGLSLSkSLFP;
    138 
    139     friend class GrSkSLFPFactory;
    140 };
    141 
    142 /**
    143  * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
    144  * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
    145  * string, then use that to create the actual GrFragmentProcessor.
    146  */
    147 class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
    148 public:
    149     /**
    150      * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
    151      * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
    152      * the produced shaders to differ), so it is important to reuse the same factory instance for
    153      * the same shader in order to avoid repeatedly re-parsing the SkSL.
    154      */
    155     GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl);
    156 
    157     const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
    158                                            size_t inputSize);
    159 
    160     const char* fName;
    161 
    162     SkSL::Compiler fCompiler;
    163 
    164     std::shared_ptr<SkSL::Program> fBaseProgram;
    165 
    166     std::vector<const SkSL::Variable*> fInputVars;
    167 
    168     std::vector<const SkSL::Variable*> fKeyVars;
    169 
    170     std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
    171 
    172     friend class GrSkSLFP;
    173 };
    174 
    175 #endif
    176