Add integer uniforms to runtime effects
Bug: skia:11803
Change-Id: I925f14be282b96355721986de6049090b35adf3d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/391856
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 4fc3718..2699db1 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -12,6 +12,13 @@
* Skia's GPU backend no longer supports NVPR. Our more recent path renderers are more
performant and are not limited to nVidia hardware.
+
+ * SkRuntimeEffect now supports uniforms of type int, int2, int3, and int4. Per the OpenGL ES
+ Shading Language Version 1.00 specification, there are few guarantees about the representation
+ or range of integral types, and operations that assume integral representation (eg, bitwise),
+ are not supported.
+ https://review.skia.org/391856
+
* * *
Milestone 90
diff --git a/gm/runtimeintrinsics.cpp b/gm/runtimeintrinsics.cpp
index fef08fe..378c589 100644
--- a/gm/runtimeintrinsics.cpp
+++ b/gm/runtimeintrinsics.cpp
@@ -444,34 +444,42 @@
/*
Specialized shader for testing relational operators.
*/
-static SkString make_bvec_sksl(const char* fn) {
+static SkString make_bvec_sksl(const char* type, const char* fn) {
// We use negative floats, to ensure that the integer variants are working with the correct
// interpretation of the data.
return SkStringPrintf(
+ "uniform %s2 v1;"
"half4 main(float2 p) {"
- " float2 v1 = float2(-2.0);"
" p.x = p.x < 0.33 ? -3.0 : (p.x < 0.66 ? -2.0 : -1.0);"
" p.y = p.y < 0.33 ? -3.0 : (p.y < 0.66 ? -2.0 : -1.0);"
" bool2 cmp = %s;"
" return half4(cmp.x ? 1.0 : 0.0, cmp.y ? 1.0 : 0.0, 0, 1);"
"}",
- fn);
+ type, fn);
}
+template <typename T = float>
static void plot_bvec(SkCanvas* canvas, const char* fn, const char* label) {
canvas->save();
draw_label(canvas, label);
- auto [effect, error] = SkRuntimeEffect::Make(make_bvec_sksl(fn));
+ const char* type = std::is_integral_v<T> ? "int" : "float";
+ auto [effect, error] = SkRuntimeEffect::Make(make_bvec_sksl(type, fn));
if (!effect) {
SkDebugf("Error: %s\n", error.c_str());
return;
}
+ T uniformData[2] = { -2, -2 };
+ sk_sp<SkData> uniforms = SkData::MakeWithCopy(uniformData, sizeof(uniformData));
+
draw_shader(canvas,
- effect->makeShader(/*uniforms=*/nullptr, /*children=*/nullptr, /*childCount=*/0,
- /*localMatrix=*/nullptr, /*isOpaque=*/false));
+ effect->makeShader(uniforms,
+ /*children=*/nullptr,
+ /*childCount=*/0,
+ /*localMatrix=*/nullptr,
+ /*isOpaque=*/false));
canvas->restore();
next_column(canvas);
@@ -485,22 +493,22 @@
canvas->translate(kPadding, kPadding);
canvas->save();
- plot_bvec(canvas, "lessThan(p, v1)", "lessThan");
- plot_bvec(canvas, "lessThan(int2(p), int2(v1))", "lessThan(int)");
- plot_bvec(canvas, "lessThanEqual(p, v1)", "lessThanEqual");
- plot_bvec(canvas, "lessThanEqual(int2(p), int2(v1))", "lessThanEqual(int)");
+ plot_bvec<float>(canvas, "lessThan(p, v1)", "lessThan");
+ plot_bvec<int> (canvas, "lessThan(int2(p), v1)", "lessThan(int)");
+ plot_bvec<float>(canvas, "lessThanEqual(p, v1)", "lessThanEqual");
+ plot_bvec<int> (canvas, "lessThanEqual(int2(p), v1)", "lessThanEqual(int)");
next_row(canvas);
- plot_bvec(canvas, "greaterThan(p, v1)", "greaterThan");
- plot_bvec(canvas, "greaterThan(int2(p), int2(v1))", "greaterThan(int)");
- plot_bvec(canvas, "greaterThanEqual(p, v1)", "greaterThanEqual");
- plot_bvec(canvas, "greaterThanEqual(int2(p), int2(v1))", "greaterThanEqual(int)");
+ plot_bvec<float>(canvas, "greaterThan(p, v1)", "greaterThan");
+ plot_bvec<int> (canvas, "greaterThan(int2(p), v1)", "greaterThan(int)");
+ plot_bvec<float>(canvas, "greaterThanEqual(p, v1)", "greaterThanEqual");
+ plot_bvec<int> (canvas, "greaterThanEqual(int2(p), v1)", "greaterThanEqual(int)");
next_row(canvas);
- plot_bvec(canvas, "equal(p, v1)", "equal");
- plot_bvec(canvas, "equal(int2(p), int2(v1))", "equal(int)");
- plot_bvec(canvas, "notEqual(p, v1)", "notEqual");
- plot_bvec(canvas, "notEqual(int2(p), int2(v1))", "notEqual(int)");
+ plot_bvec<float>(canvas, "equal(p, v1)", "equal");
+ plot_bvec<int> (canvas, "equal(int2(p), v1)", "equal(int)");
+ plot_bvec<float>(canvas, "notEqual(p, v1)", "notEqual");
+ plot_bvec<int> (canvas, "notEqual(int2(p), v1)", "notEqual(int)");
next_row(canvas);
plot_bvec(canvas, "equal( lessThanEqual(p, v1), greaterThanEqual(p, v1))", "equal(bvec)");
diff --git a/include/effects/SkRuntimeEffect.h b/include/effects/SkRuntimeEffect.h
index 76763d9..9ae7374 100644
--- a/include/effects/SkRuntimeEffect.h
+++ b/include/effects/SkRuntimeEffect.h
@@ -50,6 +50,10 @@
kFloat2x2,
kFloat3x3,
kFloat4x4,
+ kInt,
+ kInt2,
+ kInt3,
+ kInt4,
};
enum Flags {
diff --git a/src/core/SkRuntimeEffect.cpp b/src/core/SkRuntimeEffect.cpp
index be38e28..62bd8a6 100644
--- a/src/core/SkRuntimeEffect.cpp
+++ b/src/core/SkRuntimeEffect.cpp
@@ -125,6 +125,11 @@
if (type == ctx.fTypes.fFloat4x4.get()) { v->type = Type::kFloat4x4; return true; }
if (type == ctx.fTypes.fHalf4x4.get()) { v->type = Type::kFloat4x4; return true; }
+ if (type == ctx.fTypes.fInt.get()) { v->type = Type::kInt; return true; }
+ if (type == ctx.fTypes.fInt2.get()) { v->type = Type::kInt2; return true; }
+ if (type == ctx.fTypes.fInt3.get()) { v->type = Type::kInt3; return true; }
+ if (type == ctx.fTypes.fInt4.get()) { v->type = Type::kInt4; return true; }
+
return false;
}
@@ -297,6 +302,7 @@
}
size_t SkRuntimeEffect::Uniform::sizeInBytes() const {
+ static_assert(sizeof(int) == sizeof(float));
auto element_size = [](Type type) -> size_t {
switch (type) {
case Type::kFloat: return sizeof(float);
@@ -307,6 +313,11 @@
case Type::kFloat2x2: return sizeof(float) * 4;
case Type::kFloat3x3: return sizeof(float) * 9;
case Type::kFloat4x4: return sizeof(float) * 16;
+
+ case Type::kInt: return sizeof(int);
+ case Type::kInt2: return sizeof(int) * 2;
+ case Type::kInt3: return sizeof(int) * 3;
+ case Type::kInt4: return sizeof(int) * 4;
default: SkUNREACHABLE;
}
};
diff --git a/src/gpu/effects/GrSkSLFP.cpp b/src/gpu/effects/GrSkSLFP.cpp
index 8ec0a4f..b79936a 100644
--- a/src/gpu/effects/GrSkSLFP.cpp
+++ b/src/gpu/effects/GrSkSLFP.cpp
@@ -128,33 +128,29 @@
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {
+ using Type = SkRuntimeEffect::Uniform::Type;
size_t uniIndex = 0;
const GrSkSLFP& outer = _proc.cast<GrSkSLFP>();
const uint8_t* uniformData = outer.fUniforms->bytes();
for (const auto& v : outer.fEffect->uniforms()) {
- const float* data = reinterpret_cast<const float*>(uniformData + v.offset);
+ const UniformHandle handle = fUniformHandles[uniIndex++];
+ auto floatData = [=] { return SkTAddOffset<const float>(uniformData, v.offset); };
+ auto intData = [=] { return SkTAddOffset<const int>(uniformData, v.offset); };
switch (v.type) {
- case SkRuntimeEffect::Uniform::Type::kFloat:
- pdman.set1fv(fUniformHandles[uniIndex++], v.count, data);
- break;
- case SkRuntimeEffect::Uniform::Type::kFloat2:
- pdman.set2fv(fUniformHandles[uniIndex++], v.count, data);
- break;
- case SkRuntimeEffect::Uniform::Type::kFloat3:
- pdman.set3fv(fUniformHandles[uniIndex++], v.count, data);
- break;
- case SkRuntimeEffect::Uniform::Type::kFloat4:
- pdman.set4fv(fUniformHandles[uniIndex++], v.count, data);
- break;
- case SkRuntimeEffect::Uniform::Type::kFloat2x2:
- pdman.setMatrix2fv(fUniformHandles[uniIndex++], v.count, data);
- break;
- case SkRuntimeEffect::Uniform::Type::kFloat3x3:
- pdman.setMatrix3fv(fUniformHandles[uniIndex++], v.count, data);
- break;
- case SkRuntimeEffect::Uniform::Type::kFloat4x4:
- pdman.setMatrix4fv(fUniformHandles[uniIndex++], v.count, data);
- break;
+ case Type::kFloat: pdman.set1fv(handle, v.count, floatData()); break;
+ case Type::kFloat2: pdman.set2fv(handle, v.count, floatData()); break;
+ case Type::kFloat3: pdman.set3fv(handle, v.count, floatData()); break;
+ case Type::kFloat4: pdman.set4fv(handle, v.count, floatData()); break;
+
+ case Type::kFloat2x2: pdman.setMatrix2fv(handle, v.count, floatData()); break;
+ case Type::kFloat3x3: pdman.setMatrix3fv(handle, v.count, floatData()); break;
+ case Type::kFloat4x4: pdman.setMatrix4fv(handle, v.count, floatData()); break;
+
+ case Type::kInt: pdman.set1iv(handle, v.count, intData()); break;
+ case Type::kInt2: pdman.set2iv(handle, v.count, intData()); break;
+ case Type::kInt3: pdman.set3iv(handle, v.count, intData()); break;
+ case Type::kInt4: pdman.set4iv(handle, v.count, intData()); break;
+
default:
SkDEBUGFAIL("Unsupported uniform type");
break;
diff --git a/tests/SkRuntimeEffectTest.cpp b/tests/SkRuntimeEffectTest.cpp
index b295e93..9019a64 100644
--- a/tests/SkRuntimeEffectTest.cpp
+++ b/tests/SkRuntimeEffectTest.cpp
@@ -43,9 +43,8 @@
}
DEF_TEST(SkRuntimeEffectInvalid_LimitedUniformTypes, r) {
- // Runtime SkSL supports a limited set of uniform types. No bool, or int, for example:
+ // Runtime SkSL supports a limited set of uniform types. No bool, for example:
test_invalid_effect(r, "uniform bool b;" EMPTY_MAIN, "uniform");
- test_invalid_effect(r, "uniform int i;" EMPTY_MAIN, "uniform");
}
DEF_TEST(SkRuntimeEffectInvalid_NoInVariables, r) {
@@ -214,6 +213,7 @@
TestEffect effect(r, surface);
using float4 = std::array<float, 4>;
+ using int4 = std::array<int, 4>;
// Local coords
effect.build("half4 main(float2 p) { return half4(half2(p - 0.5), 0, 1); }");
@@ -226,6 +226,13 @@
effect.uniform("gColor") = float4{ 1.0f, 0.0f, 0.0f, 0.498f };
effect.test(0x7F00007F); // Tests that we clamp to valid premul
+ // Same, with integer uniforms
+ effect.build("uniform int4 gColor; half4 main() { return half4(gColor) / 255.0; }");
+ effect.uniform("gColor") = int4{ 0x00, 0x40, 0xBF, 0xFF };
+ effect.test(0xFFBF4000);
+ effect.uniform("gColor") = int4{ 0xFF, 0x00, 0x00, 0x7F };
+ effect.test(0x7F00007F); // Tests that we clamp to valid premul
+
// Test sk_FragCoord (device coords). Rotate the canvas to be sure we're seeing device coords.
// Since the surface is 2x2, we should see (0,0), (1,0), (0,1), (1,1). Multiply by 0.498 to
// make sure we're not saturating unexpectedly.
diff --git a/tools/viewer/SkSLSlide.cpp b/tools/viewer/SkSLSlide.cpp
index 58de5aa..8fa3bfc 100644
--- a/tools/viewer/SkSLSlide.cpp
+++ b/tools/viewer/SkSLSlide.cpp
@@ -199,6 +199,21 @@
}
break;
}
+ case SkRuntimeEffect::Uniform::Type::kInt:
+ case SkRuntimeEffect::Uniform::Type::kInt2:
+ case SkRuntimeEffect::Uniform::Type::kInt3:
+ case SkRuntimeEffect::Uniform::Type::kInt4: {
+ int rows = ((int)v.type - (int)SkRuntimeEffect::Uniform::Type::kInt) + 1;
+ int* i = reinterpret_cast<int*>(data);
+ for (int c = 0; c < v.count; ++c, i += rows) {
+ SkString name = v.isArray() ? SkStringPrintf("%s[%d]", v.name.c_str(), c)
+ : v.name;
+ ImGui::PushID(c);
+ ImGui::DragScalarN(name.c_str(), ImGuiDataType_S32, i, rows, 1.0f);
+ ImGui::PopID();
+ }
+ break;
+ }
}
}