Fix codegen for integer vector-scalar arithmetic in SPIR-V.

Due to missing type-checks, we would emit `OpVectorTimesScalar` when
multiplying an ivec with an int, or an `OpFDiv` when dividing an ivec
against an int.

Change-Id: Idc214dbe0ec208cb44f28b22e585584ac2ab7dae
Bug: skia:11267, skia:11788
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/388742
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:
John Stiles 2021-03-25 11:44:08 -04:00 committed by Skia Commit-Bot
parent 2febb5b423
commit d94bfdd7d8
4 changed files with 587 additions and 575 deletions

View File

@ -2242,6 +2242,14 @@ static std::unique_ptr<Expression> create_literal_1(const Context& context, cons
}
}
SpvId SPIRVCodeGenerator::writeReciprocal(const Type& type, SpvId value, OutputStream& out) {
SkASSERT(type.isFloat());
SpvId one = this->writeFloatLiteral({/*offset=*/-1, /*value=*/1, &type});
SpvId reciprocal = this->nextId(&type);
this->writeInstruction(SpvOpFDiv, this->getType(type), reciprocal, one, value, out);
return reciprocal;
}
SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Operator op,
const Type& rightType, SpvId rhs,
const Type& resultType, OutputStream& out) {
@ -2255,18 +2263,21 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs,
// handling in SPIR-V
if (this->getActualType(leftType) != this->getActualType(rightType)) {
if (leftType.isVector() && rightType.isNumber()) {
if (op.kind() == Token::Kind::TK_SLASH) {
SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
SpvId inverse = this->nextId(&rightType);
this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
rhs = inverse;
op = Token::Kind::TK_STAR;
}
if (op.kind() == Token::Kind::TK_STAR) {
SpvId result = this->nextId(&resultType);
this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
result, lhs, rhs, out);
return result;
if (resultType.componentType().isFloat()) {
switch (op.kind()) {
case Token::Kind::TK_SLASH: {
rhs = this->writeReciprocal(rightType, rhs, out);
[[fallthrough]];
}
case Token::Kind::TK_STAR: {
SpvId result = this->nextId(&resultType);
this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
result, lhs, rhs, out);
return result;
}
default:
break;
}
}
// promote number to vector
const Type& vecType = leftType;
@ -2280,11 +2291,13 @@ SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs,
rhs = vec;
operandType = &leftType;
} else if (rightType.isVector() && leftType.isNumber()) {
if (op.kind() == Token::Kind::TK_STAR) {
SpvId result = this->nextId(&resultType);
this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
result, rhs, lhs, out);
return result;
if (resultType.componentType().isFloat()) {
if (op.kind() == Token::Kind::TK_STAR) {
SpvId result = this->nextId(&resultType);
this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
result, rhs, lhs, out);
return result;
}
}
// promote number to vector
const Type& vecType = rightType;

View File

@ -314,6 +314,8 @@ private:
SpvId writeBinaryOperation(const BinaryExpression& expr, SpvOp_ ifFloat, SpvOp_ ifInt,
SpvOp_ ifUInt, OutputStream& out);
SpvId writeReciprocal(const Type& type, SpvId value, OutputStream& out);
SpvId writeBinaryExpression(const Type& leftType, SpvId lhs, Operator op,
const Type& rightType, SpvId rhs, const Type& resultType,
OutputStream& out);

View File

@ -225,8 +225,7 @@ SKSL_TEST(SkSLTernaryExpression, "shared/TernaryExpression.sksl")
SKSL_TEST(SkSLUnaryPositiveNegative, "shared/UnaryPositiveNegative.sksl")
SKSL_TEST(SkSLUnusedVariables, "shared/UnusedVariables.sksl")
SKSL_TEST(SkSLVectorConstructors, "shared/VectorConstructors.sksl")
// TODO(skia:11267, skia:11788): Enable this test on GPU once SPIR-V vector/scalar int math is fixed
SKSL_TEST_CPU(SkSLVectorScalarMath, "shared/VectorScalarMath.sksl")
SKSL_TEST(SkSLVectorScalarMath, "shared/VectorScalarMath.sksl")
/*
// Incompatible with Runtime Effects because calling a function before its definition is disallowed.

File diff suppressed because it is too large Load Diff