Honor lowp/mediump/highp precision qualifiers in IRGenerator.
This CL does not update the DSLParser to honor these precision qualifiers; that will be done in a followup. Change-Id: Ib629bc99c0e6c7afb550a381d4e3b6ccc26aa64e Bug: skia:12248 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/436337 Commit-Queue: John Stiles <johnstiles@google.com> Auto-Submit: John Stiles <johnstiles@google.com> Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
This commit is contained in:
parent
020143148f
commit
b806da4501
@ -57,6 +57,7 @@ sksl_error_tests = [
|
||||
"/sksl/errors/ForTypeMismatch.sksl",
|
||||
"/sksl/errors/FunctionParameterOfVoid.sksl",
|
||||
"/sksl/errors/GenericArgumentMismatch.sksl",
|
||||
"/sksl/errors/PrecisionQualifiersDisallowed.sksl",
|
||||
"/sksl/errors/IfTypeMismatch.sksl",
|
||||
"/sksl/errors/InVarWithInitializerExpression.sksl",
|
||||
"/sksl/errors/InterfaceBlockScope.sksl",
|
||||
@ -533,6 +534,7 @@ sksl_rte_error_tests = [
|
||||
"/sksl/runtime_errors/IllegalArrayOps.rts",
|
||||
"/sksl/runtime_errors/IllegalIndexing.rts",
|
||||
"/sksl/runtime_errors/IllegalOperators.rts",
|
||||
"/sksl/runtime_errors/IllegalPrecisionQualifiers.rts",
|
||||
"/sksl/runtime_errors/IllegalRecursionComplex.rts",
|
||||
"/sksl/runtime_errors/IllegalRecursionMutual.rts",
|
||||
"/sksl/runtime_errors/IllegalRecursionSimple.rts",
|
||||
|
4
resources/sksl/errors/PrecisionQualifiersDisallowed.sksl
Normal file
4
resources/sksl/errors/PrecisionQualifiersDisallowed.sksl
Normal file
@ -0,0 +1,4 @@
|
||||
// Precision qualifiers are only allowed in a Runtime Effect.
|
||||
void h() { highp int x; }
|
||||
void m() { mediump int x; }
|
||||
void l() { lowp int x; }
|
@ -1,9 +1,61 @@
|
||||
uniform half4 colorGreen;
|
||||
uniform half4 colorGreen, colorRed;
|
||||
|
||||
bool test_scalar() {
|
||||
mediump float mp = 0.5;
|
||||
highp float hp = mp;
|
||||
highp int ihp = 2;
|
||||
mediump int imp = ihp;
|
||||
|
||||
return mp == hp && ihp == imp;
|
||||
}
|
||||
|
||||
bool test_vector() {
|
||||
mediump vec2 mp2 = vec2(2);
|
||||
highp vec2 hp2 = mp2;
|
||||
mediump vec3 mp3 = vec3(3);
|
||||
highp vec3 hp3 = mp3;
|
||||
mediump vec4 mp4 = vec4(4);
|
||||
highp vec4 hp4 = mp4;
|
||||
|
||||
highp ivec2 ihp2 = ivec2(2);
|
||||
mediump ivec2 imp2 = ihp2;
|
||||
highp ivec3 ihp3 = ivec3(3);
|
||||
mediump ivec3 imp3 = ihp3;
|
||||
highp ivec4 ihp4 = ivec4(4);
|
||||
mediump ivec4 imp4 = ihp4;
|
||||
|
||||
return mp2 == hp2 && hp3 == mp3 && mp4 == hp4 &&
|
||||
imp2 == ihp2 && ihp3 == imp3 && imp4 == ihp4;
|
||||
}
|
||||
|
||||
bool test_matrix() {
|
||||
mediump mat2 mp2 = mat2(2);
|
||||
highp mat2 hp2 = mp2;
|
||||
mediump mat3 mp3 = mat3(3);
|
||||
highp mat3 hp3 = mp3;
|
||||
mediump mat4 mp4 = mat4(4);
|
||||
highp mat4 hp4 = mp4;
|
||||
|
||||
return mp2 == hp2 && hp3 == mp3 && mp4 == hp4;
|
||||
}
|
||||
|
||||
bool test_array() {
|
||||
mediump float mf[1]; mf[0] = 1;
|
||||
highp float hf[1]; hf[0] = 1;
|
||||
mediump vec2 mv[2]; mv[0] = vec2(0, 1); mv[1] = vec2(2, 3);
|
||||
highp vec2 hv[2]; hv[0] = vec2(0, 1); hv[1] = vec2(2, 3);
|
||||
|
||||
return mf[0] == hf[0] && hv[0] == mv[0] && mv[1] == hv[1];
|
||||
}
|
||||
|
||||
vec4 main(vec2 coords) {
|
||||
highp vec4 zero = vec4(0);
|
||||
mediump vec4 green = colorGreen;
|
||||
lowp vec4 one = vec4(1);
|
||||
mediump vec4 one = vec4(1);
|
||||
lowp vec4 green = colorGreen;
|
||||
green = green * one + zero;
|
||||
|
||||
return green * one + zero;
|
||||
highp vec4 red = colorRed;
|
||||
red = (red + zero) * one;
|
||||
|
||||
return (test_scalar() && test_vector() && test_matrix() && test_array()) ? green : red;
|
||||
}
|
||||
|
14
resources/sksl/runtime_errors/IllegalPrecisionQualifiers.rts
Normal file
14
resources/sksl/runtime_errors/IllegalPrecisionQualifiers.rts
Normal file
@ -0,0 +1,14 @@
|
||||
// Expect 10 errors
|
||||
|
||||
struct S { int i; };
|
||||
|
||||
mediump highp int no_multiple_qualifiers;
|
||||
mediump lowp int no_multiple_qualifiers_2;
|
||||
highp lowp int no_multiple_qualifiers_3;
|
||||
highp mediump lowp int no_multiple_qualifiers_4;
|
||||
highp S no_structs;
|
||||
mediump bool no_bools;
|
||||
uniform lowp colorFilter no_opaque;
|
||||
uniform highp half no_half_highp;
|
||||
uniform mediump half no_half_mediump;
|
||||
uniform lowp half no_lowp_mediump;
|
@ -294,7 +294,8 @@ void IRGenerator::checkVarDeclaration(int offset, const Modifiers& modifiers, co
|
||||
"float3, or float4 variables");
|
||||
}
|
||||
}
|
||||
int permitted = Modifiers::kConst_Flag;
|
||||
int permitted = Modifiers::kConst_Flag | Modifiers::kHighp_Flag | Modifiers::kMediump_Flag |
|
||||
Modifiers::kLowp_Flag;
|
||||
if (storage == Variable::Storage::kGlobal) {
|
||||
permitted |= Modifiers::kIn_Flag | Modifiers::kOut_Flag | Modifiers::kUniform_Flag |
|
||||
Modifiers::kFlat_Flag | Modifiers::kNoPerspective_Flag;
|
||||
@ -393,6 +394,11 @@ StatementArray IRGenerator::convertVarDeclarations(const ASTNode& decls,
|
||||
if (!baseType) {
|
||||
return {};
|
||||
}
|
||||
baseType = baseType->applyPrecisionQualifiers(fContext, modifiers, fSymbolTable.get(),
|
||||
decls.fOffset);
|
||||
if (!baseType) {
|
||||
return {};
|
||||
}
|
||||
|
||||
this->checkVarDeclaration(decls.fOffset, modifiers, baseType, storage);
|
||||
|
||||
|
@ -441,6 +441,72 @@ CoercionCost Type::coercionCost(const Type& other) const {
|
||||
return CoercionCost::Impossible();
|
||||
}
|
||||
|
||||
const Type* Type::applyPrecisionQualifiers(const Context& context,
|
||||
const Modifiers& modifiers,
|
||||
SymbolTable* symbols,
|
||||
int offset) const {
|
||||
// SkSL doesn't support low precision, so `lowp` is interpreted as medium precision.
|
||||
bool highp = modifiers.fFlags & Modifiers::kHighp_Flag;
|
||||
bool mediump = modifiers.fFlags & Modifiers::kMediump_Flag;
|
||||
bool lowp = modifiers.fFlags & Modifiers::kLowp_Flag;
|
||||
|
||||
if (!lowp && !mediump && !highp) {
|
||||
// No precision qualifiers here. Return the type as-is.
|
||||
return this;
|
||||
}
|
||||
|
||||
if (!ProgramConfig::IsRuntimeEffect(context.fConfig->fKind)) {
|
||||
// We want to discourage precision modifiers internally. Instead, use the type that
|
||||
// corresponds to the precision you need. (e.g. half vs float, short vs int)
|
||||
context.fErrors.error(offset, "precision qualifiers are not allowed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ((int(lowp) + int(mediump) + int(highp)) != 1) {
|
||||
context.fErrors.error(offset, "only one precision qualifier can be used");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Type& component = this->componentType();
|
||||
if (component.highPrecision()) {
|
||||
if (highp) {
|
||||
// Type is already high precision, and we are requesting high precision. Return as-is.
|
||||
return this;
|
||||
}
|
||||
|
||||
// Ascertain the mediump equivalent type for this type, if any.
|
||||
const Type* mediumpType;
|
||||
switch (component.numberKind()) {
|
||||
case Type::NumberKind::kFloat:
|
||||
mediumpType = context.fTypes.fHalf.get();
|
||||
break;
|
||||
|
||||
case Type::NumberKind::kSigned:
|
||||
mediumpType = context.fTypes.fShort.get();
|
||||
break;
|
||||
|
||||
case Type::NumberKind::kUnsigned:
|
||||
mediumpType = context.fTypes.fUShort.get();
|
||||
break;
|
||||
|
||||
default:
|
||||
mediumpType = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mediumpType) {
|
||||
// Convert the mediump component type into the final vector/matrix/array type as needed.
|
||||
return this->isArray()
|
||||
? symbols->addArrayDimension(mediumpType, this->columns())
|
||||
: &mediumpType->toCompound(context, this->columns(), this->rows());
|
||||
}
|
||||
}
|
||||
|
||||
context.fErrors.error(offset, "type '" + this->displayName() +
|
||||
"' does not support precision qualifiers");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Type& Type::toCompound(const Context& context, int columns, int rows) const {
|
||||
SkASSERT(this->isScalar());
|
||||
if (columns == 1 && rows == 1) {
|
||||
|
@ -23,6 +23,7 @@ namespace SkSL {
|
||||
|
||||
class BuiltinTypes;
|
||||
class Context;
|
||||
class SymbolTable;
|
||||
|
||||
struct CoercionCost {
|
||||
static CoercionCost Free() { return { 0, 0, false }; }
|
||||
@ -510,6 +511,16 @@ public:
|
||||
*/
|
||||
const Type& toCompound(const Context& context, int columns, int rows) const;
|
||||
|
||||
/**
|
||||
* Returns a type which honors the precision qualifiers set in Modifiers. e.g., kMediump_Flag
|
||||
* when applied to `float2` will return `half2`. Generates an error if the precision qualifiers
|
||||
* don't make sense, e.g. `highp bool` or `mediump MyStruct`.
|
||||
*/
|
||||
const Type* applyPrecisionQualifiers(const Context& context,
|
||||
const Modifiers& modifiers,
|
||||
SymbolTable* symbols,
|
||||
int offset) const;
|
||||
|
||||
/**
|
||||
* Coerces the passed-in expression to this type. If the types are incompatible, reports an
|
||||
* error and returns null.
|
||||
|
6
tests/sksl/errors/PrecisionQualifiersDisallowed.glsl
Normal file
6
tests/sksl/errors/PrecisionQualifiersDisallowed.glsl
Normal file
@ -0,0 +1,6 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 2: precision qualifiers are not allowed
|
||||
error: 3: precision qualifiers are not allowed
|
||||
error: 4: precision qualifiers are not allowed
|
||||
3 errors
|
@ -1,6 +1,10 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 4: 'highp' is not permitted here
|
||||
error: 5: 'mediump' is not permitted here
|
||||
error: 6: 'lowp' is not permitted here
|
||||
3 errors
|
||||
4 registers, 8 instructions:
|
||||
0 r0 = uniform32 ptr0 4
|
||||
1 r1 = uniform32 ptr0 8
|
||||
2 r2 = uniform32 ptr0 C
|
||||
3 r3 = uniform32 ptr0 10
|
||||
loop:
|
||||
4 store32 ptr1 r0
|
||||
5 store32 ptr2 r1
|
||||
6 store32 ptr3 r2
|
||||
7 store32 ptr4 r3
|
||||
|
@ -1,6 +1,56 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 4: 'highp' is not permitted here
|
||||
error: 5: 'mediump' is not permitted here
|
||||
error: 6: 'lowp' is not permitted here
|
||||
3 errors
|
||||
uniform half4 colorGreen;
|
||||
uniform half4 colorRed;
|
||||
bool test_vector_0()
|
||||
{
|
||||
half2 mp2 = half2(2.0);
|
||||
float2 hp2 = float2(mp2);
|
||||
half3 mp3 = half3(3.0);
|
||||
float3 hp3 = float3(mp3);
|
||||
half4 mp4 = half4(4.0);
|
||||
float4 hp4 = float4(mp4);
|
||||
int2 ihp2 = int2(2);
|
||||
short2 imp2 = short2(ihp2);
|
||||
int3 ihp3 = int3(3);
|
||||
short3 imp3 = short3(ihp3);
|
||||
int4 ihp4 = int4(4);
|
||||
short4 imp4 = short4(ihp4);
|
||||
return ((((float2(mp2) == hp2 && hp3 == float3(mp3)) && float4(mp4) == hp4) && int2(imp2) == ihp2) && ihp3 == int3(imp3)) && int4(imp4) == ihp4;
|
||||
}
|
||||
bool test_matrix_0()
|
||||
{
|
||||
half2x2 mp2 = half2x2(2.0);
|
||||
float2x2 hp2 = float2x2(mp2);
|
||||
half3x3 mp3 = half3x3(3.0);
|
||||
float3x3 hp3 = float3x3(mp3);
|
||||
half4x4 mp4 = half4x4(4.0);
|
||||
float4x4 hp4 = float4x4(mp4);
|
||||
return (float2x2(mp2) == hp2 && hp3 == float3x3(mp3)) && float4x4(mp4) == hp4;
|
||||
}
|
||||
bool test_array_0()
|
||||
{
|
||||
half mf[1];
|
||||
mf[0] = 1.0;
|
||||
float hf[1];
|
||||
hf[0] = 1.0;
|
||||
half2 mv[2];
|
||||
mv[0] = half2(0.0, 1.0);
|
||||
mv[1] = half2(2.0, 3.0);
|
||||
float2 hv[2];
|
||||
hv[0] = float2(0.0, 1.0);
|
||||
hv[1] = float2(2.0, 3.0);
|
||||
return (float(mf[0]) == hf[0] && hv[0] == float2(mv[0])) && float2(mv[1]) == hv[1];
|
||||
}
|
||||
float4 main(float2 coords)
|
||||
{
|
||||
float4 zero = float4(0.0);
|
||||
half4 one = half4(1.0);
|
||||
half4 green = colorGreen;
|
||||
green = half4(float4(green * one) + zero);
|
||||
float4 red = float4(colorRed);
|
||||
red = (red + zero) * float4(one);
|
||||
half _0_mp = 0.5;
|
||||
float _1_hp = float(_0_mp);
|
||||
int _2_ihp = 2;
|
||||
short _3_imp = short(_2_ihp);
|
||||
return half4((((float(_0_mp) == _1_hp && _2_ihp == int(_3_imp)) && test_vector_0()) && test_matrix_0()) && test_array_0() ? float4(green) : red);
|
||||
}
|
||||
|
13
tests/sksl/runtime_errors/IllegalPrecisionQualifiers.skvm
Normal file
13
tests/sksl/runtime_errors/IllegalPrecisionQualifiers.skvm
Normal file
@ -0,0 +1,13 @@
|
||||
### Compilation failed:
|
||||
|
||||
error: 5: only one precision qualifier can be used
|
||||
error: 6: only one precision qualifier can be used
|
||||
error: 7: only one precision qualifier can be used
|
||||
error: 8: only one precision qualifier can be used
|
||||
error: 9: type 'S' does not support precision qualifiers
|
||||
error: 10: type 'bool' does not support precision qualifiers
|
||||
error: 11: type 'colorFilter' does not support precision qualifiers
|
||||
error: 12: type 'half' does not support precision qualifiers
|
||||
error: 13: type 'half' does not support precision qualifiers
|
||||
error: 14: type 'half' does not support precision qualifiers
|
||||
10 errors
|
Loading…
Reference in New Issue
Block a user