Add Make functions for runtime blends.
This does basic plumbing work, but lacks a real implementation for the custom blend subclass. That subclass is added in the followup CL of this CL chain. Change-Id: I8db0eb42737a739b49741ffd6f4a283a2c0a9d62 Bug: skia:12080 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/417005 Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
parent
759802fdd1
commit
9300391a77
@ -21,6 +21,7 @@
|
||||
#include <vector>
|
||||
|
||||
class GrRecordingContext;
|
||||
class SkBlender;
|
||||
class SkFilterColorProgram;
|
||||
class SkImage;
|
||||
|
||||
@ -120,6 +121,10 @@ public:
|
||||
// Most shaders don't use the input color, so that parameter is optional.
|
||||
static Result MakeForShader(SkString sksl, const Options&);
|
||||
|
||||
// Blend SkSL requires an entry point that looks like:
|
||||
// vec4 main(vec4 srcColor, vec4 dstColor) { ... }
|
||||
static Result MakeForBlender(SkString sksl, const Options&);
|
||||
|
||||
// We can't use a default argument for `options` due to a bug in Clang.
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=36684
|
||||
static Result MakeForColorFilter(SkString sksl) {
|
||||
@ -128,11 +133,16 @@ public:
|
||||
static Result MakeForShader(SkString sksl) {
|
||||
return MakeForShader(std::move(sksl), Options{});
|
||||
}
|
||||
static Result MakeForBlender(SkString sksl) {
|
||||
return MakeForBlender(std::move(sksl), Options{});
|
||||
}
|
||||
|
||||
static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program);
|
||||
|
||||
static Result MakeForShader(std::unique_ptr<SkSL::Program> program);
|
||||
|
||||
static Result MakeForBlender(std::unique_ptr<SkSL::Program> program);
|
||||
|
||||
// Object that allows passing either an SkShader or SkColorFilter as a child
|
||||
struct ChildPtr {
|
||||
ChildPtr(sk_sp<SkShader> s) : shader(std::move(s)) {}
|
||||
@ -166,6 +176,8 @@ public:
|
||||
sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
|
||||
SkSpan<ChildPtr> children) const;
|
||||
|
||||
sk_sp<SkBlender> makeBlender(sk_sp<SkData> uniforms) const;
|
||||
|
||||
const SkString& source() const { return fSkSL; }
|
||||
|
||||
template <typename T>
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "include/effects/SkRuntimeEffect.h"
|
||||
#include "include/private/SkChecksum.h"
|
||||
#include "include/private/SkMutex.h"
|
||||
#include "src/core/SkBlenderBase.h"
|
||||
#include "src/core/SkCanvasPriv.h"
|
||||
#include "src/core/SkColorFilterBase.h"
|
||||
#include "src/core/SkColorSpacePriv.h"
|
||||
@ -191,14 +192,14 @@ SkRuntimeEffect::Result SkRuntimeEffect::Make(SkString sksl,
|
||||
default: SkUNREACHABLE;
|
||||
}
|
||||
|
||||
|
||||
if (sampleCoordsUsage.fRead || sampleCoordsUsage.fWrite) {
|
||||
flags |= kUsesSampleCoords_Flag;
|
||||
}
|
||||
|
||||
// Color filters are not allowed to depend on position (local or device) in any way.
|
||||
// The signature of main, and the declarations in sksl_rt_colorfilter should guarantee this.
|
||||
if (flags & kAllowColorFilter_Flag) {
|
||||
// Color filters and blends are not allowed to depend on position (local or device) in any way.
|
||||
// The signature of main, and the declarations in sksl_rt_colorfilter/sksl_rt_blend should
|
||||
// guarantee this.
|
||||
if (flags & (kAllowColorFilter_Flag | kAllowBlender_Flag)) {
|
||||
SkASSERT(!(flags & kUsesSampleCoords_Flag));
|
||||
SkASSERT(!SkSL::Analysis::ReferencesFragCoords(*program));
|
||||
}
|
||||
@ -222,6 +223,12 @@ SkRuntimeEffect::Result SkRuntimeEffect::Make(SkString sksl,
|
||||
|
||||
// Child effects that can be sampled ('shader' or 'colorFilter')
|
||||
if (varType.isEffectChild()) {
|
||||
// Runtime blends currently don't support child effects.
|
||||
if (kind == SkSL::ProgramKind::kRuntimeBlender) {
|
||||
RETURN_FAILURE("'%s' is not allowed in runtime blend",
|
||||
varType.displayName().c_str());
|
||||
}
|
||||
|
||||
Child c;
|
||||
c.name = SkString(var.name());
|
||||
c.type = child_type(varType);
|
||||
@ -294,6 +301,12 @@ SkRuntimeEffect::Result SkRuntimeEffect::MakeForShader(SkString sksl, const Opti
|
||||
return result;
|
||||
}
|
||||
|
||||
SkRuntimeEffect::Result SkRuntimeEffect::MakeForBlender(SkString sksl, const Options& options) {
|
||||
auto result = Make(std::move(sksl), options, SkSL::ProgramKind::kRuntimeBlender);
|
||||
SkASSERT(!result.effect || result.effect->allowBlender());
|
||||
return result;
|
||||
}
|
||||
|
||||
SkRuntimeEffect::Result SkRuntimeEffect::MakeForColorFilter(std::unique_ptr<SkSL::Program> program) {
|
||||
auto result = Make(std::move(program), SkSL::ProgramKind::kRuntimeColorFilter);
|
||||
SkASSERT(!result.effect || result.effect->allowColorFilter());
|
||||
@ -306,6 +319,12 @@ SkRuntimeEffect::Result SkRuntimeEffect::MakeForShader(std::unique_ptr<SkSL::Pro
|
||||
return result;
|
||||
}
|
||||
|
||||
SkRuntimeEffect::Result SkRuntimeEffect::MakeForBlender(std::unique_ptr<SkSL::Program> program) {
|
||||
auto result = Make(std::move(program), SkSL::ProgramKind::kRuntimeBlender);
|
||||
SkASSERT(!result.effect || result.effect->allowBlender());
|
||||
return result;
|
||||
}
|
||||
|
||||
sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (*make)(SkString sksl),
|
||||
SkString sksl) {
|
||||
SK_BEGIN_REQUIRE_DENSE
|
||||
@ -581,7 +600,7 @@ static sk_sp<SkData> get_xformed_uniforms(const SkRuntimeEffect* effect,
|
||||
sk_sp<SkData> uniforms = nullptr;
|
||||
auto writableData = [&]() {
|
||||
if (!uniforms) {
|
||||
uniforms = SkData::MakeWithCopy(baseUniforms->data(), baseUniforms->size());
|
||||
uniforms = SkData::MakeWithCopy(baseUniforms->data(), baseUniforms->size());
|
||||
}
|
||||
return uniforms->writable_data();
|
||||
};
|
||||
@ -1150,6 +1169,21 @@ sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms) co
|
||||
return this->makeColorFilter(std::move(uniforms), /*children=*/{});
|
||||
}
|
||||
|
||||
sk_sp<SkBlender> SkRuntimeEffect::makeBlender(sk_sp<SkData> uniforms) const {
|
||||
if (!this->allowBlender()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!uniforms) {
|
||||
uniforms = SkData::MakeEmpty();
|
||||
}
|
||||
if (uniforms->size() != this->uniformSize() || !fChildren.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
// TODO(skia:12080): create a runtime blend class
|
||||
SkDEBUGFAIL("not yet implemented");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void SkRuntimeEffect::RegisterFlattenables() {
|
||||
|
@ -138,7 +138,7 @@ DEF_TEST(SkRuntimeEffectForColorFilter, r) {
|
||||
test_invalid("uniform shader child;"
|
||||
"half4 main(half4 c) { return sample(child, c); }",
|
||||
"no match for sample(shader, half4)");
|
||||
// Coords and color in a differet order
|
||||
// Coords and color in a different order
|
||||
test_invalid("uniform shader child;"
|
||||
"half4 main(half4 c) { return sample(child, c, c.rg); }",
|
||||
"no match for sample(shader, half4, half2)");
|
||||
@ -168,6 +168,56 @@ DEF_TEST(SkRuntimeEffectForColorFilter, r) {
|
||||
"sample(colorFilter, half2, half4)");
|
||||
}
|
||||
|
||||
DEF_TEST(SkRuntimeEffectForBlender, r) {
|
||||
// Tests that the blender factory rejects or accepts certain SkSL constructs
|
||||
auto test_valid = [r](const char* sksl) {
|
||||
auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(sksl));
|
||||
REPORTER_ASSERT(r, effect, "%s", errorText.c_str());
|
||||
};
|
||||
|
||||
auto test_invalid = [r](const char* sksl, const char* expected) {
|
||||
auto [effect, errorText] = SkRuntimeEffect::MakeForBlender(SkString(sksl));
|
||||
REPORTER_ASSERT(r, !effect);
|
||||
REPORTER_ASSERT(r,
|
||||
errorText.contains(expected),
|
||||
"Expected error message to contain \"%s\". Actual message: \"%s\"",
|
||||
expected,
|
||||
errorText.c_str());
|
||||
};
|
||||
|
||||
// Color filters must use the 'half4 main(half4, half4)' signature. Any mixture of
|
||||
// float4/vec4/half4 is allowed.
|
||||
test_valid("half4 main(half4 s, half4 d) { return s; }");
|
||||
test_valid("float4 main(float4 s, float4 d) { return d; }");
|
||||
test_valid("float4 main(half4 s, float4 d) { return s; }");
|
||||
test_valid("half4 main(float4 s, half4 d) { return d; }");
|
||||
test_valid("vec4 main(half4 s, half4 d) { return s; }");
|
||||
test_valid("half4 main(vec4 s, vec4 d) { return d; }");
|
||||
test_valid("vec4 main(vec4 s, vec4 d) { return s; }");
|
||||
|
||||
// Invalid return types
|
||||
test_invalid("void main(half4 s, half4 d) {}", "'main' must return");
|
||||
test_invalid("half3 main(half4 s, half4 d) { return s.rgb; }", "'main' must return");
|
||||
|
||||
// Invalid argument types (some are valid as shaders/color filters)
|
||||
test_invalid("half4 main() { return half4(1); }", "'main' parameter");
|
||||
test_invalid("half4 main(half4 c) { return c; }", "'main' parameter");
|
||||
test_invalid("half4 main(float2 p) { return half4(1); }", "'main' parameter");
|
||||
test_invalid("half4 main(float2 p, half4 c) { return c; }", "'main' parameter");
|
||||
test_invalid("half4 main(float2 p, half4 a, half4 b) { return a; }", "'main' parameter");
|
||||
test_invalid("half4 main(half4 a, half4 b, half4 c) { return a; }", "'main' parameter");
|
||||
|
||||
// sk_FragCoord should not be available
|
||||
test_invalid("half4 main(half4 s, half4 d) { return sk_FragCoord.xy01; }",
|
||||
"unknown identifier");
|
||||
|
||||
// Child shaders are currently unsupported in blends
|
||||
test_invalid("uniform shader sh; half4 main(half4 s, half4 d) { return s; }",
|
||||
"'shader' is not allowed in runtime blend");
|
||||
test_invalid("uniform shader sh; half4 main(half4 s, half4 d) { return sample(sh, s.rg); }",
|
||||
"unknown identifier 'sample'");
|
||||
}
|
||||
|
||||
DEF_TEST(SkRuntimeEffectForShader, r) {
|
||||
// Tests that the shader factory rejects or accepts certain SkSL constructs
|
||||
auto test_valid = [r](const char* sksl) {
|
||||
|
Loading…
Reference in New Issue
Block a user