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/SkString.h"
12
13#include <vector>
14
15#if SK_SUPPORT_GPU
16#include "include/gpu/GrContextOptions.h"
17#include "include/private/GrTypesPriv.h"
18#endif
19
20class GrShaderCaps;
21class SkColorFilter;
22class SkMatrix;
23class SkShader;
24
25namespace SkSL {
26class ByteCode;
27struct PipelineStageArgs;
28struct Program;
29class SharedCompiler;
30}
31
32/*
33 * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL
34 * shading language.
35 * *
36 * This API is experimental and subject to change.
37 */
38class SK_API SkRuntimeEffect : public SkRefCnt {
39public:
40 struct Variable {
41 enum class Qualifier {
42 kUniform,
43 kIn,
44 };
45
46 enum class Type {
47 kBool,
48 kInt,
49 kFloat,
50 kFloat2,
51 kFloat3,
52 kFloat4,
53 kFloat2x2,
54 kFloat3x3,
55 kFloat4x4,
56 };
57
58 enum Flags {
59 kArray_Flag = 0x1,
60 };
61
62 SkString fName;
63 size_t fOffset;
64 Qualifier fQualifier;
65 Type fType;
66 int fCount;
67 uint32_t fFlags;
68
69#if SK_SUPPORT_GPU
70 GrSLType fGPUType;
71#endif
72
73 bool isArray() const { return SkToBool(fFlags & kArray_Flag); }
74 size_t sizeInBytes() const;
75 };
76
77 struct Varying {
78 SkString fName;
79 int fWidth; // 1 - 4 (floats)
80 };
81
82 // [Effect, ErrorText]
83 // If successful, Effect != nullptr, otherwise, ErrorText contains the reason for failure.
84 using EffectResult = std::tuple<sk_sp<SkRuntimeEffect>, SkString>;
85
86 static EffectResult Make(SkString sksl);
87
88 sk_sp<SkShader> makeShader(sk_sp<SkData> inputs, sk_sp<SkShader> children[], size_t childCount,
89 const SkMatrix* localMatrix, bool isOpaque);
90
91 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> inputs, sk_sp<SkColorFilter> children[],
92 size_t childCount);
93 sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> inputs);
94
95 const SkString& source() const { return fSkSL; }
96 uint32_t hash() const { return fHash; }
97
98 template <typename T>
99 class ConstIterable {
100 public:
101 ConstIterable(const std::vector<T>& vec) : fVec(vec) {}
102
103 using const_iterator = typename std::vector<T>::const_iterator;
104
105 const_iterator begin() const { return fVec.begin(); }
106 const_iterator end() const { return fVec.end(); }
107 size_t count() const { return fVec.size(); }
108
109 private:
110 const std::vector<T>& fVec;
111 };
112
113 // Combined size of all 'in' and 'uniform' variables. When calling makeColorFilter or
114 // makeShader, provide an SkData of this size, containing values for all of those variables.
115 size_t inputSize() const;
116
117 // Combined size of just the 'uniform' variables.
118 size_t uniformSize() const { return fUniformSize; }
119
120 ConstIterable<Variable> inputs() const { return ConstIterable<Variable>(fInAndUniformVars); }
121 ConstIterable<SkString> children() const { return ConstIterable<SkString>(fChildren); }
122 ConstIterable<Varying> varyings() const { return ConstIterable<Varying>(fVaryings); }
123
124#if SK_SUPPORT_GPU
125 // This re-compiles the program from scratch, using the supplied shader caps.
126 // This is necessary to get the correct values of settings.
127 bool toPipelineStage(const void* inputs, const GrShaderCaps* shaderCaps,
128 GrContextOptions::ShaderErrorHandler* errorHandler,
129 SkSL::PipelineStageArgs* outArgs);
130#endif
131
132 // [ByteCode, ErrorText]
133 // If successful, ByteCode != nullptr, otherwise, ErrorText contains the reason for failure.
134 using ByteCodeResult = std::tuple<std::unique_ptr<SkSL::ByteCode>, SkString>;
135
136 ByteCodeResult toByteCode(const void* inputs) const;
137
138 static void RegisterFlattenables();
139
140 ~SkRuntimeEffect();
141
142private:
143 SkRuntimeEffect(SkString sksl, std::unique_ptr<SkSL::Program> baseProgram,
144 std::vector<Variable>&& inAndUniformVars, std::vector<SkString>&& children,
145 std::vector<Varying>&& varyings, size_t uniformSize);
146
147 using SpecializeResult = std::tuple<std::unique_ptr<SkSL::Program>, SkString>;
148 SpecializeResult specialize(SkSL::Program& baseProgram, const void* inputs,
149 const SkSL::SharedCompiler&) const;
150
151 uint32_t fHash;
152 SkString fSkSL;
153
154 std::unique_ptr<SkSL::Program> fBaseProgram;
155 std::vector<Variable> fInAndUniformVars;
156 std::vector<SkString> fChildren;
157 std::vector<Varying> fVaryings;
158
159 size_t fUniformSize;
160};
161
162#endif
163