blob: f143f5308dd782c543f1edcae87c830d2876aef9 [file] [log] [blame]
Ethan Nicholas00543112018-07-31 09:44:36 -04001/*
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"
Ethan Nicholas222e2752018-10-11 11:21:34 -040012#include "GrFragmentProcessor.h"
Ethan Nicholaseace9352018-10-15 20:09:54 +000013#include "GrCoordTransform.h"
Ethan Nicholas00543112018-07-31 09:44:36 -040014#include "GrShaderCaps.h"
15#include "SkSLCompiler.h"
16#include "SkSLPipelineStageCodeGenerator.h"
17#include "SkRefCnt.h"
18#include "../private/GrSkSLFPFactoryCache.h"
Mike Klein0ec1c572018-12-04 11:52:51 -050019#include <atomic>
Ethan Nicholas00543112018-07-31 09:44:36 -040020
Ethan Nicholas78aceb22018-08-31 16:13:58 -040021#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
Robert Phillips1efecea2019-02-15 16:58:40 -050027class GrContext_Base;
Ethan Nicholas00543112018-07-31 09:44:36 -040028class GrSkSLFPFactory;
29
30class GrSkSLFP : public GrFragmentProcessor {
31public:
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() {
Mike Klein0ec1c572018-12-04 11:52:51 -050037 static std::atomic<int> nextIndex{0};
38 return nextIndex++;
Ethan Nicholas00543112018-07-31 09:44:36 -040039 }
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 */
Ethan Nicholaseace9352018-10-15 20:09:54 +000070 static std::unique_ptr<GrSkSLFP> Make(
Robert Phillips1efecea2019-02-15 16:58:40 -050071 GrContext_Base* context,
Ethan Nicholaseace9352018-10-15 20:09:54 +000072 int index,
73 const char* name,
74 const char* sksl,
75 const void* inputs,
76 size_t inputSize);
Ethan Nicholas00543112018-07-31 09:44:36 -040077
78 const char* name() const override;
79
Ethan Nicholasce008112018-08-30 09:19:50 -040080 void addChild(std::unique_ptr<GrFragmentProcessor> child);
81
Ethan Nicholas00543112018-07-31 09:44:36 -040082 std::unique_ptr<GrFragmentProcessor> clone() const override;
83
84private:
85 GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps, int fIndex,
Ethan Nicholaseace9352018-10-15 20:09:54 +000086 const char* name, const char* sksl, const void* inputs, size_t inputSize);
Ethan Nicholas00543112018-07-31 09:44:36 -040087
88 GrSkSLFP(const GrSkSLFP& other);
89
90 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
91
92 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
93
94 bool onIsEqual(const GrFragmentProcessor&) const override;
95
96 void createFactory() const;
97
98 sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
99
100 const sk_sp<GrShaderCaps> fShaderCaps;
101
102 mutable sk_sp<GrSkSLFPFactory> fFactory;
103
104 int fIndex;
105
106 const char* fName;
107
108 const char* fSkSL;
109
Ethan Nicholaseace9352018-10-15 20:09:54 +0000110 const std::unique_ptr<int8_t[]> fInputs;
Ethan Nicholas00543112018-07-31 09:44:36 -0400111
112 size_t fInputSize;
113
114 mutable SkSL::String fKey;
115
116 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
117
118 typedef GrFragmentProcessor INHERITED;
119
Ethan Nicholasce008112018-08-30 09:19:50 -0400120 friend class GrGLSLSkSLFP;
121
Ethan Nicholas00543112018-07-31 09:44:36 -0400122 friend class GrSkSLFPFactory;
123};
124
125/**
126 * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
127 * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
128 * string, then use that to create the actual GrFragmentProcessor.
129 */
Mike Klein408ef212018-10-30 15:23:00 +0000130class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
Ethan Nicholas00543112018-07-31 09:44:36 -0400131public:
132 /**
133 * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
134 * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
135 * the produced shaders to differ), so it is important to reuse the same factory instance for
136 * the same shader in order to avoid repeatedly re-parsing the SkSL.
137 */
138 GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl);
139
140 const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
141 size_t inputSize);
142
143 const char* fName;
144
145 SkSL::Compiler fCompiler;
146
147 std::shared_ptr<SkSL::Program> fBaseProgram;
148
149 std::vector<const SkSL::Variable*> fInputVars;
150
Ethan Nicholas00543112018-07-31 09:44:36 -0400151 std::vector<const SkSL::Variable*> fKeyVars;
152
153 std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
154
155 friend class GrSkSLFP;
156};
157
158#endif