aboutsummaryrefslogtreecommitdiff
path: root/src/deps/skia/include/effects/SkRuntimeEffect.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/deps/skia/include/effects/SkRuntimeEffect.h518
1 files changed, 518 insertions, 0 deletions
diff --git a/src/deps/skia/include/effects/SkRuntimeEffect.h b/src/deps/skia/include/effects/SkRuntimeEffect.h
new file mode 100644
index 000000000..d5002592a
--- /dev/null
+++ b/src/deps/skia/include/effects/SkRuntimeEffect.h
@@ -0,0 +1,518 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkRuntimeEffect_DEFINED
+#define SkRuntimeEffect_DEFINED
+
+#include "include/core/SkBlender.h"
+#include "include/core/SkColorFilter.h"
+#include "include/core/SkData.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkMatrix.h"
+#include "include/core/SkShader.h"
+#include "include/core/SkSpan.h"
+#include "include/core/SkString.h"
+#include "include/private/SkOnce.h"
+#include "include/private/SkSLSampleUsage.h"
+#include "include/private/SkTOptional.h"
+
+#include <string>
+#include <vector>
+
+#ifdef SK_ENABLE_SKSL
+
+class GrRecordingContext;
+class SkFilterColorProgram;
+class SkImage;
+class SkRuntimeImageFilter;
+
+namespace SkSL {
+class DebugTrace;
+class ErrorReporter;
+class FunctionDefinition;
+struct Program;
+enum class ProgramKind : int8_t;
+struct ProgramSettings;
+} // namespace SkSL
+
+namespace skvm {
+class Program;
+} // namespace skvm
+
+/*
+ * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL
+ * shading language.
+ *
+ * NOTE: This API is experimental and subject to change.
+ */
+class SK_API SkRuntimeEffect : public SkRefCnt {
+public:
+ // Reflected description of a uniform variable in the effect's SkSL
+ struct Uniform {
+ enum class Type {
+ kFloat,
+ kFloat2,
+ kFloat3,
+ kFloat4,
+ kFloat2x2,
+ kFloat3x3,
+ kFloat4x4,
+ kInt,
+ kInt2,
+ kInt3,
+ kInt4,
+ };
+
+ enum Flags {
+ // Uniform is an declared as an array. 'count' contains array length.
+ kArray_Flag = 0x1,
+
+ // Uniform is declared with layout(color). Colors should be supplied as unpremultiplied,
+ // extended-range (unclamped) sRGB (ie SkColor4f). The uniform will be automatically
+ // transformed to unpremultiplied extended-range working-space colors.
+ kColor_Flag = 0x2,
+ };
+
+ SkString name;
+ size_t offset;
+ Type type;
+ int count;
+ uint32_t flags;
+
+ bool isArray() const { return SkToBool(this->flags & kArray_Flag); }
+ bool isColor() const { return SkToBool(this->flags & kColor_Flag); }
+ size_t sizeInBytes() const;
+ };
+
+ // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL
+ enum class ChildType {
+ kShader,
+ kColorFilter,
+ kBlender,
+ };
+
+ struct Child {
+ SkString name;
+ ChildType type;
+ int index;
+ };
+
+ class Options {
+ public:
+ // For testing purposes, completely disable the inliner. (Normally, Runtime Effects don't
+ // run the inliner directly, but they still get an inlining pass once they are painted.)
+ bool forceNoInline = false;
+
+ private:
+ friend class SkRuntimeEffect;
+ friend class SkRuntimeEffectPriv;
+
+ // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the
+ // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are
+ // still largely ES3-unaware and can still fail or crash if post-ES2 features are used.
+ // This is only intended for use by tests and certain internally created effects.
+ bool enforceES2Restrictions = true;
+
+ // Similarly: Public SkSL does not allow access to sk_FragCoord. The semantics of that
+ // variable are confusing, and expose clients to implementation details of saveLayer and
+ // image filters.
+ bool allowFragCoord = false;
+ };
+
+ // If the effect is compiled successfully, `effect` will be non-null.
+ // Otherwise, `errorText` will contain the reason for failure.
+ struct Result {
+ sk_sp<SkRuntimeEffect> effect;
+ SkString errorText;
+ };
+
+ // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of
+ // the Skia pipeline. In all of the signatures described below, color parameters and return
+ // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or
+ // 'float4'. ('vec4' is an alias for 'float4').
+
+ // We can't use a default argument for `options` due to a bug in Clang.
+ // https://bugs.llvm.org/show_bug.cgi?id=36684
+
+ // Color filter SkSL requires an entry point that looks like:
+ // vec4 main(vec4 inColor) { ... }
+ static Result MakeForColorFilter(SkString sksl, const Options&);
+ static Result MakeForColorFilter(SkString sksl) {
+ return MakeForColorFilter(std::move(sksl), Options{});
+ }
+
+ // Shader SkSL requires an entry point that looks like:
+ // vec4 main(vec2 inCoords) { ... }
+ // -or-
+ // vec4 main(vec2 inCoords, vec4 inColor) { ... }
+ //
+ // Most shaders don't use the input color, so that parameter is optional.
+ static Result MakeForShader(SkString sksl, const Options&);
+ static Result MakeForShader(SkString sksl) {
+ return MakeForShader(std::move(sksl), Options{});
+ }
+
+ // Blend SkSL requires an entry point that looks like:
+ // vec4 main(vec4 srcColor, vec4 dstColor) { ... }
+ static Result MakeForBlender(SkString sksl, const Options&);
+ static Result MakeForBlender(SkString sksl) {
+ return MakeForBlender(std::move(sksl), Options{});
+ }
+
+ // DSL entry points
+ static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program, const Options&);
+ static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program);
+
+ static Result MakeForShader(std::unique_ptr<SkSL::Program> program, const Options&);
+ static Result MakeForShader(std::unique_ptr<SkSL::Program> program);
+ static sk_sp<SkRuntimeEffect> MakeForShader(std::unique_ptr<SkSL::Program> program,
+ const Options&, SkSL::ErrorReporter* errors);
+
+
+ static Result MakeForBlender(std::unique_ptr<SkSL::Program> program, const Options&);
+ static Result MakeForBlender(std::unique_ptr<SkSL::Program> program);
+
+ // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child
+ class ChildPtr {
+ public:
+ ChildPtr() = default;
+ ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {}
+ ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {}
+ ChildPtr(sk_sp<SkBlender> b) : fChild(std::move(b)) {}
+
+ skstd::optional<ChildType> type() const;
+
+ SkShader* shader() const;
+ SkColorFilter* colorFilter() const;
+ SkBlender* blender() const;
+ SkFlattenable* flattenable() const { return fChild.get(); }
+
+ private:
+ sk_sp<SkFlattenable> fChild;
+ };
+
+ sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms,
+ sk_sp<SkShader> children[],
+ size_t childCount,
+ const SkMatrix* localMatrix,
+ bool isOpaque) const;
+ sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms,
+ SkSpan<ChildPtr> children,
+ const SkMatrix* localMatrix,
+ bool isOpaque) const;
+
+ sk_sp<SkImage> makeImage(GrRecordingContext*,
+ sk_sp<SkData> uniforms,
+ SkSpan<ChildPtr> children,
+ const SkMatrix* localMatrix,
+ SkImageInfo resultInfo,
+ bool mipmapped) const;
+
+ sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms) const;
+ sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
+ sk_sp<SkColorFilter> children[],
+ size_t childCount) const;
+ sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
+ SkSpan<ChildPtr> children) const;
+
+ sk_sp<SkBlender> makeBlender(sk_sp<SkData> uniforms, SkSpan<ChildPtr> children = {}) const;
+
+ /**
+ * Creates a new Runtime Effect patterned after an already-existing one. The new shader behaves
+ * like the original, but also creates a debug trace of its execution at the requested
+ * coordinate. After painting with this shader, the associated DebugTrace object will contain a
+ * shader execution trace. Call `writeTrace` on the debug trace object to generate a full trace
+ * suitable for a debugger, or call `dump` to emit a human-readable trace.
+ *
+ * Debug traces are only supported on a raster (non-GPU) canvas.
+
+ * Debug traces are currently only supported on shaders. Color filter and blender tracing is a
+ * work-in-progress.
+ */
+ struct TracedShader {
+ sk_sp<SkShader> shader;
+ sk_sp<SkSL::DebugTrace> debugTrace;
+ };
+ static TracedShader MakeTraced(sk_sp<SkShader> shader, const SkIPoint& traceCoord);
+
+ // Returns the SkSL source of the runtime effect shader.
+ const std::string& source() const;
+
+ // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader,
+ // provide an SkData of this size, containing values for all of those variables.
+ size_t uniformSize() const;
+
+ SkSpan<const Uniform> uniforms() const { return SkMakeSpan(fUniforms); }
+ SkSpan<const Child> children() const { return SkMakeSpan(fChildren); }
+
+ // Returns pointer to the named uniform variable's description, or nullptr if not found
+ const Uniform* findUniform(const char* name) const;
+
+ // Returns pointer to the named child's description, or nullptr if not found
+ const Child* findChild(const char* name) const;
+
+ static void RegisterFlattenables();
+ ~SkRuntimeEffect() override;
+
+private:
+ enum Flags {
+ kUsesSampleCoords_Flag = 0x01,
+ kAllowColorFilter_Flag = 0x02,
+ kAllowShader_Flag = 0x04,
+ kAllowBlender_Flag = 0x08,
+ kSamplesOutsideMain_Flag = 0x10,
+ kUsesColorTransform_Flag = 0x20,
+ };
+
+ SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram,
+ const Options& options,
+ const SkSL::FunctionDefinition& main,
+ std::vector<Uniform>&& uniforms,
+ std::vector<Child>&& children,
+ std::vector<SkSL::SampleUsage>&& sampleUsages,
+ uint32_t flags);
+
+ sk_sp<SkRuntimeEffect> makeUnoptimizedClone();
+
+ static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind);
+
+ static Result MakeFromDSL(std::unique_ptr<SkSL::Program> program,
+ const Options& options,
+ SkSL::ProgramKind kind);
+
+ static sk_sp<SkRuntimeEffect> MakeFromDSL(std::unique_ptr<SkSL::Program> program,
+ const Options& options,
+ SkSL::ProgramKind kind,
+ SkSL::ErrorReporter* errors);
+
+ static Result MakeInternal(std::unique_ptr<SkSL::Program> program,
+ const Options& options,
+ SkSL::ProgramKind kind);
+
+ static SkSL::ProgramSettings MakeSettings(const Options& options, bool optimize);
+
+ uint32_t hash() const { return fHash; }
+ bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); }
+ bool allowShader() const { return (fFlags & kAllowShader_Flag); }
+ bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); }
+ bool allowBlender() const { return (fFlags & kAllowBlender_Flag); }
+ bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); }
+ bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); }
+
+ const SkFilterColorProgram* getFilterColorProgram();
+
+#if SK_SUPPORT_GPU
+ friend class GrSkSLFP; // fBaseProgram, fSampleUsages
+ friend class GrGLSLSkSLFP; //
+#endif
+
+ friend class SkRTShader; // fBaseProgram, fMain
+ friend class SkRuntimeBlender; //
+ friend class SkRuntimeColorFilter; //
+
+ friend class SkFilterColorProgram;
+ friend class SkRuntimeEffectPriv;
+
+ uint32_t fHash;
+
+ std::unique_ptr<SkSL::Program> fBaseProgram;
+ const SkSL::FunctionDefinition& fMain;
+ std::vector<Uniform> fUniforms;
+ std::vector<Child> fChildren;
+ std::vector<SkSL::SampleUsage> fSampleUsages;
+
+ std::unique_ptr<SkFilterColorProgram> fFilterColorProgram;
+
+ uint32_t fFlags; // Flags
+};
+
+/** Base class for SkRuntimeShaderBuilder, defined below. */
+class SkRuntimeEffectBuilder {
+public:
+ struct BuilderUniform {
+ // Copy 'val' to this variable. No type conversion is performed - 'val' must be same
+ // size as expected by the effect. Information about the variable can be queried by
+ // looking at fVar. If the size is incorrect, no copy will be performed, and debug
+ // builds will abort. If this is the result of querying a missing variable, fVar will
+ // be nullptr, and assigning will also do nothing (and abort in debug builds).
+ template <typename T>
+ std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=(
+ const T& val) {
+ if (!fVar) {
+ SkDEBUGFAIL("Assigning to missing variable");
+ } else if (sizeof(val) != fVar->sizeInBytes()) {
+ SkDEBUGFAIL("Incorrect value size");
+ } else {
+ memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset),
+ &val, sizeof(val));
+ }
+ return *this;
+ }
+
+ BuilderUniform& operator=(const SkMatrix& val) {
+ if (!fVar) {
+ SkDEBUGFAIL("Assigning to missing variable");
+ } else if (fVar->sizeInBytes() != 9 * sizeof(float)) {
+ SkDEBUGFAIL("Incorrect value size");
+ } else {
+ float* data = SkTAddOffset<float>(fOwner->writableUniformData(),
+ (ptrdiff_t)fVar->offset);
+ data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6);
+ data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7);
+ data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8);
+ }
+ return *this;
+ }
+
+ template <typename T>
+ bool set(const T val[], const int count) {
+ static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable");
+ if (!fVar) {
+ SkDEBUGFAIL("Assigning to missing variable");
+ return false;
+ } else if (sizeof(T) * count != fVar->sizeInBytes()) {
+ SkDEBUGFAIL("Incorrect value size");
+ return false;
+ } else {
+ memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset),
+ val, sizeof(T) * count);
+ }
+ return true;
+ }
+
+ SkRuntimeEffectBuilder* fOwner;
+ const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found
+ };
+
+ struct BuilderChild {
+ template <typename T> BuilderChild& operator=(sk_sp<T> val) {
+ if (!fChild) {
+ SkDEBUGFAIL("Assigning to missing child");
+ } else {
+ fOwner->fChildren[(size_t)fChild->index] = std::move(val);
+ }
+ return *this;
+ }
+
+ BuilderChild& operator=(std::nullptr_t) {
+ if (!fChild) {
+ SkDEBUGFAIL("Assigning to missing child");
+ } else {
+ fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{};
+ }
+ return *this;
+ }
+
+ SkRuntimeEffectBuilder* fOwner;
+ const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found
+ };
+
+ const SkRuntimeEffect* effect() const { return fEffect.get(); }
+
+ BuilderUniform uniform(const char* name) { return { this, fEffect->findUniform(name) }; }
+ BuilderChild child(const char* name) {
+ const SkRuntimeEffect::Child* child = fEffect->findChild(name);
+ return { this, child };
+ }
+
+protected:
+ SkRuntimeEffectBuilder() = delete;
+ explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)
+ : fEffect(std::move(effect))
+ , fUniforms(SkData::MakeZeroInitialized(fEffect->uniformSize()))
+ , fChildren(fEffect->children().size()) {}
+ explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms)
+ : fEffect(std::move(effect))
+ , fUniforms(std::move(uniforms))
+ , fChildren(fEffect->children().size()) {}
+
+ SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default;
+ SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default;
+
+ SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete;
+ SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete;
+
+ sk_sp<SkData> uniforms() { return fUniforms; }
+ SkRuntimeEffect::ChildPtr* children() { return fChildren.data(); }
+ size_t numChildren() { return fChildren.size(); }
+
+private:
+ void* writableUniformData() {
+ if (!fUniforms->unique()) {
+ fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
+ }
+ return fUniforms->writable_data();
+ }
+
+ sk_sp<SkRuntimeEffect> fEffect;
+ sk_sp<SkData> fUniforms;
+ std::vector<SkRuntimeEffect::ChildPtr> fChildren;
+};
+
+/**
+ * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
+ *
+ * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
+ *
+ * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
+ * provides named access to the 'uniform' variables in that block, as well as named access
+ * to a list of child shader slots. Usage:
+ *
+ * sk_sp<SkRuntimeEffect> effect = ...;
+ * SkRuntimeShaderBuilder builder(effect);
+ * builder.uniform("some_uniform_float") = 3.14f;
+ * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
+ * builder.child("some_child_effect") = mySkImage->makeShader(...);
+ * ...
+ * sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
+ *
+ * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
+ * so can be used as-is or serve as inspiration for other interfaces or binding techniques.
+ */
+class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder {
+public:
+ explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
+ // This is currently required by Android Framework but may go away if that dependency
+ // can be removed.
+ SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default;
+ ~SkRuntimeShaderBuilder();
+
+ sk_sp<SkShader> makeShader(const SkMatrix* localMatrix, bool isOpaque);
+ sk_sp<SkImage> makeImage(GrRecordingContext*,
+ const SkMatrix* localMatrix,
+ SkImageInfo resultInfo,
+ bool mipmapped);
+
+private:
+ using INHERITED = SkRuntimeEffectBuilder;
+
+ explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms)
+ : INHERITED(std::move(effect), std::move(uniforms)) {}
+
+ friend class SkRuntimeImageFilter;
+};
+
+/**
+ * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders.
+ */
+class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder {
+public:
+ explicit SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect>);
+ ~SkRuntimeBlendBuilder();
+
+ SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete;
+ SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete;
+
+ sk_sp<SkBlender> makeBlender();
+
+private:
+ using INHERITED = SkRuntimeEffectBuilder;
+};
+
+#endif // SK_ENABLE_SKSL
+
+#endif // SkRuntimeEffect_DEFINED