[sksl] Disallow boolean uniforms

Booleans and structs/interface blocks that transitively contain a
boolean member are no longer allowed to be used as a uniform. This is
because SPIR-V and WGSL currently disallow OpTypeBool in host-shareable
storage classes.

Change-Id: I10315c7f261ff10a07636265968a91d9c421da55
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/542776
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: John Stiles <johnstiles@google.com>
Commit-Queue: Arman Uguray <armansito@google.com>
This commit is contained in:
Arman Uguray 2022-05-20 10:49:37 -07:00 committed by SkCQ
parent 3aed21ce0e
commit bd969a089d
7 changed files with 134 additions and 19 deletions

View File

@ -80,6 +80,7 @@ sksl_error_tests = [
"/sksl/errors/InvalidOutParams.rts",
"/sksl/errors/InvalidToken.rts",
"/sksl/errors/InvalidUnary.rts",
"/sksl/errors/InvalidUniformTypes.sksl",
"/sksl/errors/InVarWithInitializerExpression.sksl",
"/sksl/errors/LayoutInFunctions.sksl",
"/sksl/errors/LayoutInInterfaceBlock.sksl",

View File

@ -0,0 +1,41 @@
uniform short s;
uniform short2 s2;
uniform short3 s3;
uniform short4 s4;
uniform bool b;
uniform bool2 b2;
uniform bool3 b3;
uniform bool4 b4;
// Structs and interface blocks are valid SkSL uniforms but their member types are restricted.
struct InvalidStruct1 {
float f; // valid
bool b; // invalid
};
struct InvalidStruct2 {
InvalidStruct1 s;
};
uniform InvalidStruct1 st1;
uniform InvalidStruct2 st2;
uniform invalidBlock {
float f; // valid
bool b; // invalid
} ib;
half4 main(float2 coords) {
return half4(0);
}
/*%%*
variables of type 'bool' may not be uniform
variables of type 'bool2' may not be uniform
variables of type 'bool3' may not be uniform
variables of type 'bool4' may not be uniform
variables of type 'bool' may not be uniform
variables of type 'bool' may not be uniform
variables of type 'bool' may not be uniform
*%%*/

View File

@ -1,11 +1,11 @@
/*#pragma settings UnfoldShortCircuitAsTernary*/
uniform bool x;
uniform bool y;
uniform int i;
uniform int j;
void main() {
bool x = bool(i);
bool y = bool(j);
bool andXY = x && y;
bool orXY = x || y;
bool combo = (x && y) || (x || y);

View File

@ -15,7 +15,57 @@
#include "src/sksl/SkSLThreadContext.h"
namespace SkSL {
namespace {
static bool check_valid_uniform_type(Position pos,
const Type* t,
const Context& context,
bool topLevel = true) {
const Type& ct = t->componentType();
// In RuntimeEffects we only allow a restricted set of types, namely shader/blender/colorFilter,
// 32-bit signed integers, 16-bit and 32-bit floats, and their composites.
{
bool error = false;
if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
if (t->isEffectChild() ||
((t->isScalar() || t->isVector()) && ct.isSigned() && ct.bitWidth() == 32) ||
((t->isScalar() || t->isVector() || t->isMatrix()) && ct.isFloat())) {
return true;
}
// Everything else is an error.
error = true;
}
// We disallow boolean uniforms in SkSL since they are not well supported by backend
// platforms and drivers.
if (error || (ct.isBoolean() && (t->isScalar() || t->isVector()))) {
context.fErrors->error(
pos, "variables of type '" + t->displayName() + "' may not be uniform");
return false;
}
}
// In non-RTE SkSL we allow structs and interface blocks to be uniforms but we must make sure
// their fields are allowed.
if (t->isStruct()) {
for (const Type::Field& field : t->fields()) {
if (!check_valid_uniform_type(
field.fPosition, field.fType, context, /*topLevel=*/false)) {
// Emit a "caused by" line only for the top-level uniform type and not for any
// nested structs.
if (topLevel) {
context.fErrors->error(pos, "caused by:");
}
return false;
}
}
}
return true;
}
} // namespace
std::unique_ptr<Statement> VarDeclaration::clone() const {
// Cloning a VarDeclaration is inherently problematic, as we normally expect a one-to-one
@ -85,23 +135,13 @@ void VarDeclaration::ErrorCheck(const Context& context,
if ((modifiers.fFlags & Modifiers::kIn_Flag) && (modifiers.fFlags & Modifiers::kUniform_Flag)) {
context.fErrors->error(pos, "'in uniform' variables not permitted");
}
if ((modifiers.fFlags & Modifiers::kUniform_Flag)) {
check_valid_uniform_type(pos, baseType, context);
}
if (ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
if (modifiers.fFlags & Modifiers::kIn_Flag) {
context.fErrors->error(pos, "'in' variables not permitted in runtime effects");
}
if (modifiers.fFlags & Modifiers::kUniform_Flag) {
auto validUniformType = [](const Type& t) {
const Type& ct = t.componentType();
return t.isEffectChild() ||
((t.isScalar() || t.isVector()) && ct.isSigned() && ct.bitWidth() == 32) ||
((t.isScalar() || t.isVector() || t.isMatrix()) && ct.isFloat());
};
if (!validUniformType(*baseType)) {
context.fErrors->error(
pos,
"variables of type '" + baseType->displayName() + "' may not be uniform");
}
}
}
if (baseType->isEffectChild() && !(modifiers.fFlags & Modifiers::kUniform_Flag)) {
context.fErrors->error(pos,

View File

@ -0,0 +1,33 @@
### Compilation failed:
error: 6: variables of type 'bool' may not be uniform
uniform bool b;
^^^^^^^^^^^^^^^
error: 7: variables of type 'bool2' may not be uniform
uniform bool2 b2;
^^^^^^^^^^^^^^^^
error: 8: variables of type 'bool3' may not be uniform
uniform bool3 b3;
^^^^^^^^^^^^^^^^
error: 9: variables of type 'bool4' may not be uniform
uniform bool4 b4;
^^^^^^^^^^^^^^^^
error: 14: variables of type 'bool' may not be uniform
bool b; // invalid
^^^^^^
error: 21: caused by:
uniform InvalidStruct1 st1;
^^^^^^^^^^^^^^^^^^^^^^^^^^
error: 14: variables of type 'bool' may not be uniform
bool b; // invalid
^^^^^^
error: 22: caused by:
uniform InvalidStruct2 st2;
^^^^^^^^^^^^^^^^^^^^^^^^^^
error: 26: variables of type 'bool' may not be uniform
bool b; // invalid
^^^^^^^
error: 24: caused by:
uniform invalidBlock {
^^^^^^^^^^^^
10 errors

View File

@ -1,10 +1,10 @@
#version 400
out vec4 sk_FragColor;
uniform bool x;
uniform bool y;
uniform int i;
uniform int j;
void main() {
bool x = bool(i);
bool y = bool(j);
bool andXY = x ? y : false;
bool orXY = x ? true : y;
bool combo = (x ? y : false) ? true : (x ? true : y);

View File

@ -1,10 +1,10 @@
out vec4 sk_FragColor;
uniform bool x;
uniform bool y;
uniform int i;
uniform int j;
void main() {
bool x = bool(i);
bool y = bool(j);
bool andXY = x && y;
bool orXY = x || y;
bool combo = x && y || (x || y);