1/*
2 * Copyright 2019 Google LLC
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 SkRuntimeEffect_DEFINED
9#define SkRuntimeEffect_DEFINED
10
11#include "include/core/SkData.h"
12#include "include/core/SkMatrix.h"
13#include "include/core/SkString.h"
14#include "include/private/GrTypesPriv.h"
15#include "include/private/SkSLSampleUsage.h"
16
17#include <string>
18#include <vector>
19
20#if SK_SUPPORT_GPU
21#include "include/gpu/GrContextOptions.h"
22#endif
23
24class GrShaderCaps;
25class SkColorFilter;
26class SkShader;
27
28namespace SkSL {
29class ByteCode;
30struct PipelineStageArgs;
31struct Program;
32class SharedCompiler;
33} // namespace SkSL
34
35/*
36 * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL
37 * shading language.
38 *
39 * NOTE: This API is experimental and subject to change.
40 */
41class SK_API SkRuntimeEffect : public SkRefCnt {
42public:
43 struct Uniform {
44 enum class Type {
45 kFloat,
46 kFloat2,
47 kFloat3,
48 kFloat4,
49 kFloat2x2,
50 kFloat3x3,
51 kFloat4x4,
52 };
53
54 enum Flags {
55 kArray_Flag = 0x1,
56 kMarker_Flag = 0x2,
57 kMarkerNormals_Flag = 0x4,
58 kSRGBUnpremul_Flag = 0x8,
59 };
60
61 SkString fName;
62 size_t fOffset;
63 Type fType;
64 GrSLType fGPUType;
65 int fCount;
66 uint32_t fFlags;
67 uint32_t fMarker;
68
69 bool isArray() const { return SkToBool(fFlags & kArray_Flag); }
70 size_t sizeInBytes() const;
71 };
72
73 struct Varying {
74 SkString fName;
75 int fWidth; // 1 - 4 (floats)
76 };
77
78 // [Effect, ErrorText]
79 // If successful, Effect != nullptr, otherwise, ErrorText contains the reason for failure.
80 using EffectResult = std::tuple<sk_sp<SkRuntimeEffect>, SkString>;
81 static EffectResult Make(SkString sksl);
82
83 sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms,
84 sk_sp<SkShader> children[],
85 size_t childCount,
86 const SkMatrix* localMatrix,
87 bool isOpaque);
88
89 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms);
90 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
91 sk_sp<SkColorFilter> children[],
92 size_t childCount);
93
94 const SkString& source() const { return fSkSL; }
95 uint32_t hash() const { return fHash; }
96
97 template <typename T>
98 class ConstIterable {
99 public:
100 ConstIterable(const std::vector<T>& vec) : fVec(vec) {}
101
102 using const_iterator = typename std::vector<T>::const_iterator;
103
104 const_iterator begin() const { return fVec.begin(); }
105 const_iterator end() const { return fVec.end(); }
106 size_t count() const { return fVec.size(); }
107
108 private:
109 const std::vector<T>& fVec;
110 };
111
112 // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader,
113 // provide an SkData of this size, containing values for all of those variables.
114 size_t uniformSize() const;
115
116 ConstIterable<Uniform> uniforms() const { return ConstIterable<Uniform>(fUniforms); }
117 ConstIterable<SkString> children() const { return ConstIterable<SkString>(fChildren); }
118 ConstIterable<Varying> varyings() const { return ConstIterable<Varying>(fVaryings); }
119
120 // Returns pointer to the named uniform variable's description, or nullptr if not found
121 const Uniform* findUniform(const char* name) const;
122
123 // Returns index of the named child, or -1 if not found
124 int findChild(const char* name) const;
125
126 bool usesSampleCoords() const { return fUsesSampleCoords; }
127
128 static void RegisterFlattenables();
129 ~SkRuntimeEffect() override;
130
131private:
132 SkRuntimeEffect(SkString sksl,
133 std::unique_ptr<SkSL::Program> baseProgram,
134 std::vector<Uniform>&& uniforms,
135 std::vector<SkString>&& children,
136 std::vector<SkSL::SampleUsage>&& sampleUsages,
137 std::vector<Varying>&& varyings,
138 bool usesSampleCoords,
139 bool allowColorFilter);
140
141#if SK_SUPPORT_GPU
142 friend class GrSkSLFP; // toPipelineStage
143 friend class GrGLSLSkSLFP; // fSampleUsages
144
145 // This re-compiles the program from scratch, using the supplied shader caps.
146 // This is necessary to get the correct values of settings.
147 bool toPipelineStage(const GrShaderCaps* shaderCaps,
148 GrContextOptions::ShaderErrorHandler* errorHandler,
149 SkSL::PipelineStageArgs* outArgs);
150#endif
151
152 friend class SkRTShader; // toByteCode
153 friend class SkRuntimeColorFilter; //
154
155 // [ByteCode, ErrorText]
156 // If successful, ByteCode != nullptr, otherwise, ErrorText contains the reason for failure.
157 using ByteCodeResult = std::tuple<std::unique_ptr<SkSL::ByteCode>, SkString>;
158 ByteCodeResult toByteCode() const;
159
160
161 uint32_t fHash;
162 SkString fSkSL;
163
164 std::unique_ptr<SkSL::Program> fBaseProgram;
165 std::vector<Uniform> fUniforms;
166 std::vector<SkString> fChildren;
167 std::vector<SkSL::SampleUsage> fSampleUsages;
168 std::vector<Varying> fVaryings;
169
170 bool fUsesSampleCoords;
171 bool fAllowColorFilter;
172};
173
174/**
175 * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
176 *
177 * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
178 *
179 * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
180 * provides named access to the 'uniform' variables in that block, as well as named access
181 * to a list of child shader slots. Usage:
182 *
183 * sk_sp<SkRuntimeEffect> effect = ...;
184 * SkRuntimeShaderBuilder builder(effect);
185 * builder.uniform("some_uniform_float") = 3.14f;
186 * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
187 * builder.child("some_child_effect") = mySkImage->makeShader(...);
188 * ...
189 * sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
190 *
191 * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
192 * so can be used as-is or serve as inspiration for other interfaces or binding techniques.
193 */
194struct SkRuntimeShaderBuilder {
195 SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
196 ~SkRuntimeShaderBuilder();
197
198 struct BuilderUniform {
199 // Copy 'val' to this variable. No type conversion is performed - 'val' must be same
200 // size as expected by the effect. Information about the variable can be queried by
201 // looking at fVar. If the size is incorrect, no copy will be performed, and debug
202 // builds will abort. If this is the result of querying a missing variable, fVar will
203 // be nullptr, and assigning will also do nothing (and abort in debug builds).
204 template <typename T>
205 std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=(
206 const T& val) {
207 if (!fVar) {
208 SkDEBUGFAIL("Assigning to missing variable");
209 } else if (sizeof(val) != fVar->sizeInBytes()) {
210 SkDEBUGFAIL("Incorrect value size");
211 } else {
212 memcpy(SkTAddOffset<void>(fOwner->fUniforms->writable_data(), fVar->fOffset),
213 &val, sizeof(val));
214 }
215 return *this;
216 }
217
218 BuilderUniform& operator=(const SkMatrix& val) {
219 if (!fVar) {
220 SkDEBUGFAIL("Assigning to missing variable");
221 } else if (fVar->sizeInBytes() != 9 * sizeof(float)) {
222 SkDEBUGFAIL("Incorrect value size");
223 } else {
224 float* data = SkTAddOffset<float>(fOwner->fUniforms->writable_data(),
225 fVar->fOffset);
226 data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6);
227 data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7);
228 data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8);
229 }
230 return *this;
231 }
232
233 SkRuntimeShaderBuilder* fOwner;
234 const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found
235 };
236
237 struct BuilderChild {
238 BuilderChild& operator=(const sk_sp<SkShader>& val);
239
240 SkRuntimeShaderBuilder* fOwner;
241 int fIndex; // -1 if the child was not found
242 };
243
244 BuilderUniform uniform(const char* name) { return { this, fEffect->findUniform(name) }; }
245 BuilderChild child(const char* name) { return { this, fEffect->findChild(name) }; }
246
247 sk_sp<SkShader> makeShader(const SkMatrix* localMatrix, bool isOpaque);
248
249 sk_sp<SkRuntimeEffect> fEffect;
250 sk_sp<SkData> fUniforms;
251 std::vector<sk_sp<SkShader>> fChildren;
252};
253
254#endif
255