mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-12-16 08:27:05 +00:00
spirv-reader: polyfill scalar reflect
Fixed: tint:1018 Change-Id: I60916d6c4ac4ae8c1a88763c12acf83d19bb2e68 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/58821 Commit-Queue: David Neto <dneto@google.com> Auto-Submit: David Neto <dneto@google.com> Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: Ben Clayton <bclayton@chromium.org>
This commit is contained in:
@@ -3996,6 +3996,7 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
|
||||
// WGSL does not have scalar form of the normalize builtin.
|
||||
// The answer would be 1 anyway, so return that directly.
|
||||
return {ty_.F32(), builder_.Expr(1.0f)};
|
||||
|
||||
case GLSLstd450FaceForward: {
|
||||
// If dot(Nref, Incident) < 0, the result is Normal, otherwise -Normal.
|
||||
// Also: select(-normal,normal, Incident*Nref < 0)
|
||||
@@ -4021,6 +4022,21 @@ TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
|
||||
builder_.Expr(0.0f))})};
|
||||
}
|
||||
|
||||
case GLSLstd450Reflect: {
|
||||
// Compute Incident - 2 * Normal * Normal * Incident
|
||||
auto incident = MakeOperand(inst, 2);
|
||||
auto normal = MakeOperand(inst, 3);
|
||||
TINT_ASSERT(Reader, incident.type->Is<F32>());
|
||||
TINT_ASSERT(Reader, normal.type->Is<F32>());
|
||||
return {
|
||||
ty_.F32(),
|
||||
builder_.Sub(
|
||||
incident.expr,
|
||||
builder_.Mul(2.0f, builder_.Mul(normal.expr,
|
||||
builder_.Mul(normal.expr,
|
||||
incident.expr))))};
|
||||
}
|
||||
|
||||
case GLSLstd450Refract: {
|
||||
// It's a complicated expression. Compute it in two dimensions, but
|
||||
// with a 0-valued y component in both the incident and normal vectors,
|
||||
@@ -4701,6 +4717,10 @@ void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
|
||||
// The "normal" operand expression is used twice in code generation.
|
||||
require_named_const_def(inst, 2);
|
||||
break;
|
||||
case GLSLstd450Reflect:
|
||||
require_named_const_def(inst, 2); // Incident
|
||||
require_named_const_def(inst, 3); // Normal
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -717,7 +717,6 @@ INSTANTIATE_TEST_SUITE_P(Samples,
|
||||
{"FMax", "max"}, // WGSL max promises more for NaN
|
||||
{"FMin", "min"}, // WGSL min promises more for NaN
|
||||
{"Pow", "pow"},
|
||||
{"Reflect", "reflect"},
|
||||
{"Step", "step"},
|
||||
}));
|
||||
|
||||
@@ -1913,6 +1912,145 @@ TEST_F(SpvParserTest, GlslStd450_FaceForward_Vector) {
|
||||
EXPECT_THAT(body, HasSubstr(expected));
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GlslStd450_Reflect_Scalar) {
|
||||
const auto assembly = Preamble() + R"(
|
||||
%98 = OpFAdd %float %f1 %f1 ; has only one use
|
||||
%99 = OpFAdd %float %f2 %f2 ; has only one use
|
||||
%1 = OpExtInst %float %glsl Reflect %98 %99
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
|
||||
auto fe = p->function_emitter(100);
|
||||
EXPECT_TRUE(fe.EmitBody()) << p->error();
|
||||
const auto body = ToString(p->builder(), fe.ast_body());
|
||||
// The %99 sum only has one use. Ensure it is evaluated only once by
|
||||
// making a let-declaration for it, since it is the normal operand to
|
||||
// the builtin function, and code generation uses it twice.
|
||||
const auto* expected = R"(VariableDeclStatement{
|
||||
VariableConst{
|
||||
x_98
|
||||
none
|
||||
undefined
|
||||
__f32
|
||||
{
|
||||
Binary[not set]{
|
||||
Identifier[not set]{f1}
|
||||
add
|
||||
Identifier[not set]{f1}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VariableDeclStatement{
|
||||
VariableConst{
|
||||
x_99
|
||||
none
|
||||
undefined
|
||||
__f32
|
||||
{
|
||||
Binary[not set]{
|
||||
Identifier[not set]{f2}
|
||||
add
|
||||
Identifier[not set]{f2}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VariableDeclStatement{
|
||||
VariableConst{
|
||||
x_1
|
||||
none
|
||||
undefined
|
||||
__f32
|
||||
{
|
||||
Binary[not set]{
|
||||
Identifier[not set]{x_98}
|
||||
subtract
|
||||
Binary[not set]{
|
||||
ScalarConstructor[not set]{2.000000}
|
||||
multiply
|
||||
Binary[not set]{
|
||||
Identifier[not set]{x_99}
|
||||
multiply
|
||||
Binary[not set]{
|
||||
Identifier[not set]{x_99}
|
||||
multiply
|
||||
Identifier[not set]{x_98}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})";
|
||||
|
||||
EXPECT_THAT(body, HasSubstr(expected)) << body;
|
||||
}
|
||||
|
||||
TEST_F(SpvParserTest, GlslStd450_Reflect_Vector) {
|
||||
const auto assembly = Preamble() + R"(
|
||||
%98 = OpFAdd %v2float %v2f1 %v2f1
|
||||
%99 = OpFAdd %v2float %v2f2 %v2f2
|
||||
%1 = OpExtInst %v2float %glsl Reflect %98 %99
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
)";
|
||||
auto p = parser(test::Assemble(assembly));
|
||||
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
|
||||
auto fe = p->function_emitter(100);
|
||||
EXPECT_TRUE(fe.EmitBody()) << p->error();
|
||||
const auto body = ToString(p->builder(), fe.ast_body());
|
||||
const auto* expected = R"(VariableDeclStatement{
|
||||
VariableConst{
|
||||
x_98
|
||||
none
|
||||
undefined
|
||||
__vec_2__f32
|
||||
{
|
||||
Binary[not set]{
|
||||
Identifier[not set]{v2f1}
|
||||
add
|
||||
Identifier[not set]{v2f1}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VariableDeclStatement{
|
||||
VariableConst{
|
||||
x_99
|
||||
none
|
||||
undefined
|
||||
__vec_2__f32
|
||||
{
|
||||
Binary[not set]{
|
||||
Identifier[not set]{v2f2}
|
||||
add
|
||||
Identifier[not set]{v2f2}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VariableDeclStatement{
|
||||
VariableConst{
|
||||
x_1
|
||||
none
|
||||
undefined
|
||||
__vec_2__f32
|
||||
{
|
||||
Call[not set]{
|
||||
Identifier[not set]{reflect}
|
||||
(
|
||||
Identifier[not set]{x_98}
|
||||
Identifier[not set]{x_99}
|
||||
)
|
||||
}
|
||||
})";
|
||||
|
||||
EXPECT_THAT(body, HasSubstr(expected)) << body;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace spirv
|
||||
} // namespace reader
|
||||
|
||||
Reference in New Issue
Block a user