Add support for remaining GLSL builtin geometric functions
Bug: b/127804400
Test: dEQP-VK.glsl.operator.geometric.*
Change-Id: I63d852c2978be4c1966886cf24c489cc7c286964
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27128
Tested-by: Chris Forbes <chrisforbes@google.com>
Presubmit-Ready: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 25ce989..c42c923 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -1688,13 +1688,7 @@
auto srcLHS = GenericValue(this, routine, insn.word(3));
auto srcRHS = GenericValue(this, routine, insn.word(4));
- SIMD::Float result = srcLHS[0] * srcRHS[0];
-
- for (auto i = 1u; i < lhsType.sizeInComponents; i++)
- {
- result += srcLHS[i] * srcRHS[i];
- }
-
+ SIMD::Float result = Dot(lhsType.sizeInComponents, srcLHS, srcRHS);
dst.emplace(0, result);
}
@@ -1956,11 +1950,105 @@
}
break;
}
+ case GLSLstd450Reflect:
+ {
+ auto I = GenericValue(this, routine, insn.word(5));
+ auto N = GenericValue(this, routine, insn.word(6));
+
+ SIMD::Float d = Dot(type.sizeInComponents, I, N);
+
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ dst.emplace(i, I[i] - SIMD::Float(2.0f) * d * N[i]);
+ }
+ break;
+ }
+ case GLSLstd450Refract:
+ {
+ auto I = GenericValue(this, routine, insn.word(5));
+ auto N = GenericValue(this, routine, insn.word(6));
+ auto eta = GenericValue(this, routine, insn.word(7));
+
+ SIMD::Float d = Dot(type.sizeInComponents, I, N);
+ SIMD::Float k = SIMD::Float(1.0f) - eta[0] * eta[0] * (SIMD::Float(1.0f) - d * d);
+ SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
+ SIMD::Float t = (eta[0] * d + Sqrt(k));
+
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ dst.emplace(i, As<SIMD::Float>(pos & As<SIMD::Int>(eta[0] * I[i] - t * N[i])));
+ }
+ break;
+ }
+ case GLSLstd450FaceForward:
+ {
+ auto N = GenericValue(this, routine, insn.word(5));
+ auto I = GenericValue(this, routine, insn.word(6));
+ auto Nref = GenericValue(this, routine, insn.word(7));
+
+ SIMD::Float d = Dot(type.sizeInComponents, I, Nref);
+ SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
+
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ dst.emplace(i, As<SIMD::Float>((neg & As<SIMD::Int>(N[i])) | (~neg & As<SIMD::Int>(-N[i]))));
+ }
+ break;
+ }
+ case GLSLstd450Length:
+ {
+ auto x = GenericValue(this, routine, insn.word(5));
+ SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
+
+ dst.emplace(0, Sqrt(d));
+ break;
+ }
+ case GLSLstd450Normalize:
+ {
+ auto x = GenericValue(this, routine, insn.word(5));
+ SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
+ SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d);
+
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ dst.emplace(i, invLength * x[i]);
+ }
+ break;
+ }
+ case GLSLstd450Distance:
+ {
+ auto p0 = GenericValue(this, routine, insn.word(5));
+ auto p1 = GenericValue(this, routine, insn.word(6));
+ auto p0Type = getType(getObject(insn.word(5)).type);
+
+ // sqrt(dot(p0-p1, p0-p1))
+ SIMD::Float d = (p0[0] - p1[0]) * (p0[0] - p1[0]);
+
+ for (auto i = 1u; i < p0Type.sizeInComponents; i++)
+ {
+ d += (p0[i] - p1[i]) * (p0[i] - p1[i]);
+ }
+
+ dst.emplace(0, Sqrt(d));
+ break;
+ }
default:
UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
}
}
+ SIMD::Float SpirvShader::Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const
+ {
+ SIMD::Float d = x[0] * y[0];
+
+ for (auto i = 1u; i < numComponents; i++)
+ {
+ d += x[i] * y[i];
+ }
+
+ return d;
+ }
+
void SpirvShader::EmitAny(InsnIterator insn, SpirvRoutine *routine) const
{
auto &type = getType(insn.word(1));
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index c645a3f..1c3c5a3 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -41,6 +41,7 @@
{
// Forward declarations.
class SpirvRoutine;
+ class GenericValue;
// SIMD contains types that represent multiple scalars packed into a single
// vector data type. Types in the SIMD namespace provide a semantic hint
@@ -456,6 +457,9 @@
// OpcodeName returns the name of the opcode op.
// If NDEBUG is defined, then OpcodeName will only return the numerical code.
static std::string OpcodeName(spv::Op op);
+
+ // Helper as we often need to take dot products as part of doing other things.
+ SIMD::Float Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const;
};
class SpirvRoutine