Support integer uniforms in CanvasKit runtime effects
These were added to SkRuntimeEffects, but we need to do a bit of fixup in the CK bindings. Note that 'getUniformFloatCount' is now poorly named, but the idea still stands: it's how many total scalar values are required. Bug: skia:11803 Change-Id: If464156d8e6240736e324ef833e57ba7d53f55a0 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/394476 Reviewed-by: Kevin Lubick <kjlubick@google.com> Reviewed-by: Joe Gregorio <jcgregorio@google.com> Commit-Queue: Brian Osman <brianosman@google.com>
This commit is contained in:
parent
48d13b2e2c
commit
9be7683222
@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
- Add `drawPatch` to `Canvas`.
|
||||
- Add `Strut` as a `RectHeightStyle` enum.
|
||||
- `CanvasKit.RuntimeEffect` now supports integer uniforms in the SkSL. These are still passed
|
||||
to `RuntimeEffect.makeShader` as floats (like all other uniforms), and will be converted to
|
||||
integers internally, to match the expectations of the shader.
|
||||
|
||||
## [0.25.1] - 2021-03-30
|
||||
|
||||
|
@ -631,24 +631,51 @@ struct RuntimeEffectUniform {
|
||||
int columns;
|
||||
int rows;
|
||||
int slot; // the index into the uniforms array that this uniform begins.
|
||||
bool isInteger;
|
||||
};
|
||||
|
||||
RuntimeEffectUniform fromUniform(const SkRuntimeEffect::Uniform& u) {
|
||||
RuntimeEffectUniform su;
|
||||
su.rows = u.count; // arrayLength
|
||||
su.columns = 1;
|
||||
su.rows = u.count; // arrayLength
|
||||
su.columns = 1;
|
||||
su.isInteger = false;
|
||||
using Type = SkRuntimeEffect::Uniform::Type;
|
||||
switch (u.type) {
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat: break;
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat2: su.columns = 2; break;
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat3: su.columns = 3; break;
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat4: su.columns = 4; break;
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat2x2: su.columns = 2; su.rows *= 2; break;
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat3x3: su.columns = 3; su.rows *= 3; break;
|
||||
case SkRuntimeEffect::Uniform::Type::kFloat4x4: su.columns = 4; su.rows *= 4; break;
|
||||
case Type::kFloat: break;
|
||||
case Type::kFloat2: su.columns = 2; break;
|
||||
case Type::kFloat3: su.columns = 3; break;
|
||||
case Type::kFloat4: su.columns = 4; break;
|
||||
case Type::kFloat2x2: su.columns = 2; su.rows *= 2; break;
|
||||
case Type::kFloat3x3: su.columns = 3; su.rows *= 3; break;
|
||||
case Type::kFloat4x4: su.columns = 4; su.rows *= 4; break;
|
||||
case Type::kInt: su.isInteger = true; break;
|
||||
case Type::kInt2: su.columns = 2; su.isInteger = true; break;
|
||||
case Type::kInt3: su.columns = 3; su.isInteger = true; break;
|
||||
case Type::kInt4: su.columns = 4; su.isInteger = true; break;
|
||||
}
|
||||
su.slot = u.offset / sizeof(float);
|
||||
return su;
|
||||
}
|
||||
|
||||
void castUniforms(void* data, size_t dataLen, const SkRuntimeEffect& effect) {
|
||||
if (dataLen != effect.uniformSize()) {
|
||||
// Incorrect number of uniforms. Our code below could read/write off the end of the buffer.
|
||||
// However, shader creation is going to fail anyway, so just do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
float* fltData = reinterpret_cast<float*>(data);
|
||||
for (const auto& u : effect.uniforms()) {
|
||||
RuntimeEffectUniform reu = fromUniform(u);
|
||||
if (reu.isInteger) {
|
||||
// The SkSL is expecting integers in the uniform data
|
||||
for (int i = 0; i < reu.columns * reu.rows; ++i) {
|
||||
int numAsInt = static_cast<int>(fltData[reu.slot + i]);
|
||||
fltData[reu.slot + i] = SkBits2Float(numAsInt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// These objects have private destructors / delete methods - I don't think
|
||||
@ -1663,6 +1690,7 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
.function("_makeShader", optional_override([](SkRuntimeEffect& self, uintptr_t fPtr, size_t fLen, bool isOpaque,
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
void* inputData = reinterpret_cast<void*>(fPtr);
|
||||
castUniforms(inputData, fLen, self);
|
||||
sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
|
||||
|
||||
OptionalMatrix localMatrix(mPtr);
|
||||
@ -1672,6 +1700,7 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
uintptr_t /** SkShader*[] */cPtrs, size_t cLen,
|
||||
uintptr_t /* SkScalar* */ mPtr)->sk_sp<SkShader> {
|
||||
void* inputData = reinterpret_cast<void*>(fPtr);
|
||||
castUniforms(inputData, fLen, self);
|
||||
sk_sp<SkData> inputs = SkData::MakeFromMalloc(inputData, fLen);
|
||||
|
||||
sk_sp<SkShader>* children = new sk_sp<SkShader>[cLen];
|
||||
@ -1703,9 +1732,10 @@ EMSCRIPTEN_BINDINGS(Skia) {
|
||||
}));
|
||||
|
||||
value_object<RuntimeEffectUniform>("RuntimeEffectUniform")
|
||||
.field("columns", &RuntimeEffectUniform::columns)
|
||||
.field("rows", &RuntimeEffectUniform::rows)
|
||||
.field("slot", &RuntimeEffectUniform::slot);
|
||||
.field("columns", &RuntimeEffectUniform::columns)
|
||||
.field("rows", &RuntimeEffectUniform::rows)
|
||||
.field("slot", &RuntimeEffectUniform::slot)
|
||||
.field("isInteger", &RuntimeEffectUniform::isInteger);
|
||||
|
||||
constant("rt_effect", true);
|
||||
#endif
|
||||
|
@ -18,12 +18,12 @@ describe('Runtime shader effects', () => {
|
||||
// it will draw blank.
|
||||
const spiralSkSL = `
|
||||
uniform float rad_scale;
|
||||
uniform float2 in_center;
|
||||
uniform int2 in_center;
|
||||
uniform float4 in_colors0;
|
||||
uniform float4 in_colors1;
|
||||
|
||||
half4 main(float2 p) {
|
||||
float2 pp = p - in_center;
|
||||
float2 pp = p - float2(in_center);
|
||||
float radius = sqrt(dot(pp, pp));
|
||||
radius = sqrt(radius);
|
||||
float angle = atan(pp.y / pp.x);
|
||||
@ -45,11 +45,18 @@ half4 main(float2 p) {
|
||||
|
||||
expect(spiral.getUniformCount() ).toEqual(4);
|
||||
expect(spiral.getUniformFloatCount()).toEqual(11);
|
||||
const center = spiral.getUniform(1);
|
||||
expect(center).toBeTruthy('could not fetch numbered uniform');
|
||||
expect(center.slot ).toEqual(1);
|
||||
expect(center.columns ).toEqual(2);
|
||||
expect(center.rows ).toEqual(1);
|
||||
expect(center.isInteger).toEqual(true);
|
||||
const color_0 = spiral.getUniform(2);
|
||||
expect(color_0).toBeTruthy('could not fetch numbered uniform');
|
||||
expect(color_0.slot ).toEqual(3);
|
||||
expect(color_0.columns).toEqual(4);
|
||||
expect(color_0.rows ).toEqual(1);
|
||||
expect(color_0.slot ).toEqual(3);
|
||||
expect(color_0.columns ).toEqual(4);
|
||||
expect(color_0.rows ).toEqual(1);
|
||||
expect(color_0.isInteger).toEqual(false);
|
||||
expect(spiral.getUniformName(2)).toEqual('in_colors0');
|
||||
|
||||
const canvas = surface.getCanvas();
|
||||
|
Loading…
Reference in New Issue
Block a user