SpirvShader: Move GLSLstd450 handling to new cpp file Bug: b/145336353 Change-Id: I39a5bffc1784c7b35ab9c4016658f4532d6ce5fb Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/38810 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: Alexis Hétu <sugoi@google.com> Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/BUILD.gn b/src/Pipeline/BUILD.gn index e17084a..62f28cb 100644 --- a/src/Pipeline/BUILD.gn +++ b/src/Pipeline/BUILD.gn
@@ -38,9 +38,10 @@ "SamplerCore.cpp", "SetupRoutine.cpp", "ShaderCore.cpp", - "SpirvShader.cpp", - "SpirvShaderSampling.cpp", "SpirvShader_dbg.cpp", + "SpirvShader.cpp", + "SpirvShaderGLSLstd450.cpp", + "SpirvShaderSampling.cpp", "VertexProgram.cpp", "VertexRoutine.cpp", ]
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index 441ff43..ec916b5 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -33,8 +33,6 @@ namespace { - constexpr float PI = 3.141592653589793f; - VkFormat SpirvFormatToVulkanFormat(spv::ImageFormat format) { switch (format) @@ -3313,928 +3311,6 @@ return EmitResult::Continue; } - SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const - { - auto &type = getType(insn.word(1)); - auto &dst = state->createIntermediate(insn.word(2), type.sizeInComponents); - auto extInstIndex = static_cast<GLSLstd450>(insn.word(4)); - - switch (extInstIndex) - { - case GLSLstd450FAbs: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Abs(src.Float(i))); - } - break; - } - case GLSLstd450SAbs: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Abs(src.Int(i))); - } - break; - } - case GLSLstd450Cross: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - dst.move(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2)); - dst.move(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0)); - dst.move(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1)); - break; - } - case GLSLstd450Floor: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Floor(src.Float(i))); - } - break; - } - case GLSLstd450Trunc: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Trunc(src.Float(i))); - } - break; - } - case GLSLstd450Ceil: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Ceil(src.Float(i))); - } - break; - } - case GLSLstd450Fract: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Frac(src.Float(i))); - } - break; - } - case GLSLstd450Round: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Round(src.Float(i))); - } - break; - } - case GLSLstd450RoundEven: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto x = Round(src.Float(i)); - // dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src)); - dst.move(i, x + ((SIMD::Float(CmpLT(x, src.Float(i)) & SIMD::Int(1)) * SIMD::Float(2.0f)) - SIMD::Float(1.0f)) * - SIMD::Float(CmpEQ(Frac(src.Float(i)), SIMD::Float(0.5f)) & SIMD::Int(1)) * SIMD::Float(Int4(x) & SIMD::Int(1))); - } - break; - } - case GLSLstd450FMin: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Min(lhs.Float(i), rhs.Float(i))); - } - break; - } - case GLSLstd450FMax: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Max(lhs.Float(i), rhs.Float(i))); - } - break; - } - case GLSLstd450SMin: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Min(lhs.Int(i), rhs.Int(i))); - } - break; - } - case GLSLstd450SMax: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Max(lhs.Int(i), rhs.Int(i))); - } - break; - } - case GLSLstd450UMin: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Min(lhs.UInt(i), rhs.UInt(i))); - } - break; - } - case GLSLstd450UMax: - { - auto lhs = GenericValue(this, state, insn.word(5)); - auto rhs = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Max(lhs.UInt(i), rhs.UInt(i))); - } - break; - } - case GLSLstd450Step: - { - auto edge = GenericValue(this, state, insn.word(5)); - auto x = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f))); - } - break; - } - case GLSLstd450SmoothStep: - { - auto edge0 = GenericValue(this, state, insn.word(5)); - auto edge1 = GenericValue(this, state, insn.word(6)); - auto x = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto tx = Min(Max((x.Float(i) - edge0.Float(i)) / - (edge1.Float(i) - edge0.Float(i)), SIMD::Float(0.0f)), SIMD::Float(1.0f)); - dst.move(i, tx * tx * (Float4(3.0f) - Float4(2.0f) * tx)); - } - break; - } - case GLSLstd450FMix: - { - auto x = GenericValue(this, state, insn.word(5)); - auto y = GenericValue(this, state, insn.word(6)); - auto a = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i)); - } - break; - } - case GLSLstd450FClamp: - { - auto x = GenericValue(this, state, insn.word(5)); - auto minVal = GenericValue(this, state, insn.word(6)); - auto maxVal = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i))); - } - break; - } - case GLSLstd450SClamp: - { - auto x = GenericValue(this, state, insn.word(5)); - auto minVal = GenericValue(this, state, insn.word(6)); - auto maxVal = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i))); - } - break; - } - case GLSLstd450UClamp: - { - auto x = GenericValue(this, state, insn.word(5)); - auto minVal = GenericValue(this, state, insn.word(6)); - auto maxVal = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i))); - } - break; - } - case GLSLstd450FSign: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f)); - auto pos = As<SIMD::Int>(CmpNLE(src.Float(i), SIMD::Float(+0.0f))) & As<SIMD::Int>(SIMD::Float(1.0f)); - dst.move(i, neg | pos); - } - break; - } - case GLSLstd450SSign: - { - auto src = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1); - auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1); - dst.move(i, neg | pos); - } - break; - } - case GLSLstd450Reflect: - { - auto I = GenericValue(this, state, insn.word(5)); - auto N = GenericValue(this, state, insn.word(6)); - - SIMD::Float d = Dot(type.sizeInComponents, I, N); - - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i)); - } - break; - } - case GLSLstd450Refract: - { - auto I = GenericValue(this, state, insn.word(5)); - auto N = GenericValue(this, state, insn.word(6)); - auto eta = GenericValue(this, state, insn.word(7)); - - SIMD::Float d = Dot(type.sizeInComponents, I, N); - SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d); - SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f)); - SIMD::Float t = (eta.Float(0) * d + Sqrt(k)); - - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i))); - } - break; - } - case GLSLstd450FaceForward: - { - auto N = GenericValue(this, state, insn.word(5)); - auto I = GenericValue(this, state, insn.word(6)); - auto Nref = GenericValue(this, state, 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++) - { - auto n = N.Float(i); - dst.move(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n))); - } - break; - } - case GLSLstd450Length: - { - auto x = GenericValue(this, state, insn.word(5)); - SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x); - - dst.move(0, Sqrt(d)); - break; - } - case GLSLstd450Normalize: - { - auto x = GenericValue(this, state, 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.move(i, invLength * x.Float(i)); - } - break; - } - case GLSLstd450Distance: - { - auto p0 = GenericValue(this, state, insn.word(5)); - auto p1 = GenericValue(this, state, insn.word(6)); - auto p0Type = getType(p0.type); - - // sqrt(dot(p0-p1, p0-p1)) - SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0)); - - for (auto i = 1u; i < p0Type.sizeInComponents; i++) - { - d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i)); - } - - dst.move(0, Sqrt(d)); - break; - } - case GLSLstd450Modf: - { - auto val = GenericValue(this, state, insn.word(5)); - auto ptrId = Object::ID(insn.word(6)); - auto ptrTy = getType(getObject(ptrId).type); - auto ptr = GetPointerToData(ptrId, 0, state); - bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass); - // TODO: GLSL modf() takes an output parameter and thus the pointer is assumed - // to be in bounds even for inactive lanes. - // - Clarify the SPIR-V spec. - // - Eliminate lane masking and assume interleaving. - auto robustness = OutOfBoundsBehavior::UndefinedBehavior; - - for (auto i = 0u; i < type.sizeInComponents; i++) - { - SIMD::Float whole, frac; - std::tie(whole, frac) = Modf(val.Float(i)); - dst.move(i, frac); - auto p = ptr + (i * sizeof(float)); - if (interleavedByLane) { p = InterleaveByLane(p); } - p.Store(whole, robustness, state->activeLaneMask()); - } - break; - } - case GLSLstd450ModfStruct: - { - auto val = GenericValue(this, state, insn.word(5)); - auto valTy = getType(val.type); - - for (auto i = 0u; i < valTy.sizeInComponents; i++) - { - SIMD::Float whole, frac; - std::tie(whole, frac) = Modf(val.Float(i)); - dst.move(i, frac); - dst.move(i + valTy.sizeInComponents, whole); - } - break; - } - case GLSLstd450PackSnorm4x8: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & - SIMD::Int(0xFF)) | - ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & - SIMD::Int(0xFF)) << 8) | - ((SIMD::Int(Round(Min(Max(val.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & - SIMD::Int(0xFF)) << 16) | - ((SIMD::Int(Round(Min(Max(val.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & - SIMD::Int(0xFF)) << 24)); - break; - } - case GLSLstd450PackUnorm4x8: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) | - ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) | - ((SIMD::UInt(Round(Min(Max(val.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) | - ((SIMD::UInt(Round(Min(Max(val.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24)); - break; - } - case GLSLstd450PackSnorm2x16: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) & - SIMD::Int(0xFFFF)) | - ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) & - SIMD::Int(0xFFFF)) << 16)); - break; - } - case GLSLstd450PackUnorm2x16: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) & - SIMD::UInt(0xFFFF)) | - ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) & - SIMD::UInt(0xFFFF)) << 16)); - break; - } - case GLSLstd450PackHalf2x16: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, FloatToHalfBits(val.UInt(0), false) | FloatToHalfBits(val.UInt(1), true)); - break; - } - case GLSLstd450UnpackSnorm4x8: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, Min(Max(SIMD::Float(((val.Int(0)<<24) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); - dst.move(1, Min(Max(SIMD::Float(((val.Int(0)<<16) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); - dst.move(2, Min(Max(SIMD::Float(((val.Int(0)<<8) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); - dst.move(3, Min(Max(SIMD::Float(((val.Int(0)) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); - break; - } - case GLSLstd450UnpackUnorm4x8: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); - dst.move(1, SIMD::Float(((val.UInt(0)>>8) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); - dst.move(2, SIMD::Float(((val.UInt(0)>>16) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); - dst.move(3, SIMD::Float(((val.UInt(0)>>24) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); - break; - } - case GLSLstd450UnpackSnorm2x16: - { - auto val = GenericValue(this, state, insn.word(5)); - // clamp(f / 32767.0, -1.0, 1.0) - dst.move(0, Min(Max(SIMD::Float(As<SIMD::Int>((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16)) * - SIMD::Float(1.0f / float(0x7FFF0000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); - dst.move(1, Min(Max(SIMD::Float(As<SIMD::Int>(val.UInt(0) & SIMD::UInt(0xFFFF0000))) * SIMD::Float(1.0f / float(0x7FFF0000)), - SIMD::Float(-1.0f)), SIMD::Float(1.0f))); - break; - } - case GLSLstd450UnpackUnorm2x16: - { - auto val = GenericValue(this, state, insn.word(5)); - // f / 65535.0 - dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16) * SIMD::Float(1.0f / float(0xFFFF0000))); - dst.move(1, SIMD::Float(val.UInt(0) & SIMD::UInt(0xFFFF0000)) * SIMD::Float(1.0f / float(0xFFFF0000))); - break; - } - case GLSLstd450UnpackHalf2x16: - { - auto val = GenericValue(this, state, insn.word(5)); - dst.move(0, halfToFloatBits(val.UInt(0) & SIMD::UInt(0x0000FFFF))); - dst.move(1, halfToFloatBits((val.UInt(0) & SIMD::UInt(0xFFFF0000)) >> 16)); - break; - } - case GLSLstd450Fma: - { - auto a = GenericValue(this, state, insn.word(5)); - auto b = GenericValue(this, state, insn.word(6)); - auto c = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, FMA(a.Float(i), b.Float(i), c.Float(i))); - } - break; - } - case GLSLstd450Frexp: - { - auto val = GenericValue(this, state, insn.word(5)); - auto ptrId = Object::ID(insn.word(6)); - auto ptrTy = getType(getObject(ptrId).type); - auto ptr = GetPointerToData(ptrId, 0, state); - bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass); - // TODO: GLSL frexp() takes an output parameter and thus the pointer is assumed - // to be in bounds even for inactive lanes. - // - Clarify the SPIR-V spec. - // - Eliminate lane masking and assume interleaving. - auto robustness = OutOfBoundsBehavior::UndefinedBehavior; - - for (auto i = 0u; i < type.sizeInComponents; i++) - { - SIMD::Float significand; - SIMD::Int exponent; - std::tie(significand, exponent) = Frexp(val.Float(i)); - - dst.move(i, significand); - - auto p = ptr + (i * sizeof(float)); - if (interleavedByLane) { p = InterleaveByLane(p); } - p.Store(exponent, robustness, state->activeLaneMask()); - } - break; - } - case GLSLstd450FrexpStruct: - { - auto val = GenericValue(this, state, insn.word(5)); - auto numComponents = getType(val.type).sizeInComponents; - for (auto i = 0u; i < numComponents; i++) - { - auto significandAndExponent = Frexp(val.Float(i)); - dst.move(i, significandAndExponent.first); - dst.move(i + numComponents, significandAndExponent.second); - } - break; - } - case GLSLstd450Ldexp: - { - auto significand = GenericValue(this, state, insn.word(5)); - auto exponent = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - // Assumes IEEE 754 - auto in = significand.Float(i); - auto significandExponent = Exponent(in); - auto combinedExponent = exponent.Int(i) + significandExponent; - auto isSignificandZero = SIMD::UInt(CmpEQ(significand.Int(i), SIMD::Int(0))); - auto isSignificandInf = SIMD::UInt(IsInf(in)); - auto isSignificandNaN = SIMD::UInt(IsNan(in)); - auto isExponentNotTooSmall = SIMD::UInt(CmpGE(combinedExponent, SIMD::Int(-126))); - auto isExponentNotTooLarge = SIMD::UInt(CmpLE(combinedExponent, SIMD::Int(128))); - auto isExponentInBounds = isExponentNotTooSmall & isExponentNotTooLarge; - - SIMD::UInt v; - v = significand.UInt(i) & SIMD::UInt(0x7FFFFF); // Add significand. - v |= (SIMD::UInt(combinedExponent + SIMD::Int(126)) << SIMD::UInt(23)); // Add exponent. - v &= isExponentInBounds; // Clear v if the exponent is OOB. - - v |= significand.UInt(i) & SIMD::UInt(0x80000000); // Add sign bit. - v |= ~isExponentNotTooLarge & SIMD::UInt(0x7F800000); // Mark as inf if the exponent is too great. - - // If the input significand is zero, inf or nan, just return the - // input significand. - auto passthrough = isSignificandZero | isSignificandInf | isSignificandNaN; - v = (v & ~passthrough) | (significand.UInt(i) & passthrough); - - dst.move(i, As<SIMD::Float>(v)); - } - break; - } - case GLSLstd450Radians: - { - auto degrees = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, degrees.Float(i) * SIMD::Float(PI / 180.0f)); - } - break; - } - case GLSLstd450Degrees: - { - auto radians = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, radians.Float(i) * SIMD::Float(180.0f / PI)); - } - break; - } - case GLSLstd450Sin: - { - auto radians = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Sin(radians.Float(i))); - } - break; - } - case GLSLstd450Cos: - { - auto radians = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Cos(radians.Float(i))); - } - break; - } - case GLSLstd450Tan: - { - auto radians = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Tan(radians.Float(i))); - } - break; - } - case GLSLstd450Asin: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Asin(val.Float(i))); - } - break; - } - case GLSLstd450Acos: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Acos(val.Float(i))); - } - break; - } - case GLSLstd450Atan: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Atan(val.Float(i))); - } - break; - } - case GLSLstd450Sinh: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Sinh(val.Float(i))); - } - break; - } - case GLSLstd450Cosh: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Cosh(val.Float(i))); - } - break; - } - case GLSLstd450Tanh: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Tanh(val.Float(i))); - } - break; - } - case GLSLstd450Asinh: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Asinh(val.Float(i))); - } - break; - } - case GLSLstd450Acosh: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Acosh(val.Float(i))); - } - break; - } - case GLSLstd450Atanh: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Atanh(val.Float(i))); - } - break; - } - case GLSLstd450Atan2: - { - auto x = GenericValue(this, state, insn.word(5)); - auto y = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Atan2(x.Float(i), y.Float(i))); - } - break; - } - case GLSLstd450Pow: - { - auto x = GenericValue(this, state, insn.word(5)); - auto y = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Pow(x.Float(i), y.Float(i))); - } - break; - } - case GLSLstd450Exp: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Exp(val.Float(i))); - } - break; - } - case GLSLstd450Log: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Log(val.Float(i))); - } - break; - } - case GLSLstd450Exp2: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Exp2(val.Float(i))); - } - break; - } - case GLSLstd450Log2: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Log2(val.Float(i))); - } - break; - } - case GLSLstd450Sqrt: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, Sqrt(val.Float(i))); - } - break; - } - case GLSLstd450InverseSqrt: - { - auto val = GenericValue(this, state, insn.word(5)); - Decorations d; - ApplyDecorationsForId(&d, insn.word(5)); - if (d.RelaxedPrecision) - { - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, RcpSqrt_pp(val.Float(i))); - } - } - else - { - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, SIMD::Float(1.0f) / Sqrt(val.Float(i))); - } - } - break; - } - case GLSLstd450Determinant: - { - auto mat = GenericValue(this, state, insn.word(5)); - auto numComponents = getType(mat.type).sizeInComponents; - switch (numComponents) - { - case 4: // 2x2 - dst.move(0, Determinant( - mat.Float(0), mat.Float(1), - mat.Float(2), mat.Float(3))); - break; - case 9: // 3x3 - dst.move(0, Determinant( - mat.Float(0), mat.Float(1), mat.Float(2), - mat.Float(3), mat.Float(4), mat.Float(5), - mat.Float(6), mat.Float(7), mat.Float(8))); - break; - case 16: // 4x4 - dst.move(0, Determinant( - mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3), - mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7), - mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11), - mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15))); - break; - default: - UNREACHABLE("GLSLstd450Determinant can only operate with square matrices. Got %d elements", int(numComponents)); - } - break; - } - case GLSLstd450MatrixInverse: - { - auto mat = GenericValue(this, state, insn.word(5)); - auto numComponents = getType(mat.type).sizeInComponents; - switch (numComponents) - { - case 4: // 2x2 - { - auto inv = MatrixInverse( - mat.Float(0), mat.Float(1), - mat.Float(2), mat.Float(3)); - for (uint32_t i = 0; i < inv.size(); i++) - { - dst.move(i, inv[i]); - } - break; - } - case 9: // 3x3 - { - auto inv = MatrixInverse( - mat.Float(0), mat.Float(1), mat.Float(2), - mat.Float(3), mat.Float(4), mat.Float(5), - mat.Float(6), mat.Float(7), mat.Float(8)); - for (uint32_t i = 0; i < inv.size(); i++) - { - dst.move(i, inv[i]); - } - break; - } - case 16: // 4x4 - { - auto inv = MatrixInverse( - mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3), - mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7), - mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11), - mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15)); - for (uint32_t i = 0; i < inv.size(); i++) - { - dst.move(i, inv[i]); - } - break; - } - default: - UNREACHABLE("GLSLstd450MatrixInverse can only operate with square matrices. Got %d elements", int(numComponents)); - } - break; - } - case GLSLstd450IMix: - { - UNREACHABLE("GLSLstd450IMix has been removed from the specification"); - break; - } - case GLSLstd450PackDouble2x32: - { - UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450PackDouble2x32)"); - break; - } - case GLSLstd450UnpackDouble2x32: - { - UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450UnpackDouble2x32)"); - break; - } - case GLSLstd450FindILsb: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto v = val.UInt(i); - dst.move(i, Cttz(v, true) | CmpEQ(v, SIMD::UInt(0))); - } - break; - } - case GLSLstd450FindSMsb: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto v = val.UInt(i) ^ As<SIMD::UInt>(CmpLT(val.Int(i), SIMD::Int(0))); - dst.move(i, SIMD::UInt(31) - Ctlz(v, false)); - } - break; - } - case GLSLstd450FindUMsb: - { - auto val = GenericValue(this, state, insn.word(5)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, SIMD::UInt(31) - Ctlz(val.UInt(i), false)); - } - break; - } - case GLSLstd450InterpolateAtCentroid: - { - UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); - break; - } - case GLSLstd450InterpolateAtSample: - { - UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); - break; - } - case GLSLstd450InterpolateAtOffset: - { - UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); - break; - } - case GLSLstd450NMin: - { - auto x = GenericValue(this, state, insn.word(5)); - auto y = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, NMin(x.Float(i), y.Float(i))); - } - break; - } - case GLSLstd450NMax: - { - auto x = GenericValue(this, state, insn.word(5)); - auto y = GenericValue(this, state, insn.word(6)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - dst.move(i, NMax(x.Float(i), y.Float(i))); - } - break; - } - case GLSLstd450NClamp: - { - auto x = GenericValue(this, state, insn.word(5)); - auto minVal = GenericValue(this, state, insn.word(6)); - auto maxVal = GenericValue(this, state, insn.word(7)); - for (auto i = 0u; i < type.sizeInComponents; i++) - { - auto clamp = NMin(NMax(x.Float(i), minVal.Float(i)), maxVal.Float(i)); - dst.move(i, clamp); - } - break; - } - default: - UNREACHABLE("ExtInst %d", int(extInstIndex)); - break; - } - - return EmitResult::Continue; - } - std::memory_order SpirvShader::MemoryOrder(spv::MemorySemanticsMask memorySemantics) { auto control = static_cast<uint32_t>(memorySemantics) & static_cast<uint32_t>(
diff --git a/src/Pipeline/SpirvShaderGLSLstd450.cpp b/src/Pipeline/SpirvShaderGLSLstd450.cpp new file mode 100644 index 0000000..f9485ca --- /dev/null +++ b/src/Pipeline/SpirvShaderGLSLstd450.cpp
@@ -0,0 +1,951 @@ +// Copyright 2019 The SwiftShader Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "SpirvShader.hpp" + +#include "ShaderCore.hpp" + +#include <spirv/unified1/spirv.hpp> +#include <spirv/unified1/GLSL.std.450.h> + +namespace +{ + constexpr float PI = 3.141592653589793f; +} + +namespace sw { + +SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const +{ + auto &type = getType(insn.word(1)); + auto &dst = state->createIntermediate(insn.word(2), type.sizeInComponents); + auto extInstIndex = static_cast<GLSLstd450>(insn.word(4)); + + switch (extInstIndex) + { + case GLSLstd450FAbs: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Abs(src.Float(i))); + } + break; + } + case GLSLstd450SAbs: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Abs(src.Int(i))); + } + break; + } + case GLSLstd450Cross: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + dst.move(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2)); + dst.move(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0)); + dst.move(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1)); + break; + } + case GLSLstd450Floor: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Floor(src.Float(i))); + } + break; + } + case GLSLstd450Trunc: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Trunc(src.Float(i))); + } + break; + } + case GLSLstd450Ceil: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Ceil(src.Float(i))); + } + break; + } + case GLSLstd450Fract: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Frac(src.Float(i))); + } + break; + } + case GLSLstd450Round: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Round(src.Float(i))); + } + break; + } + case GLSLstd450RoundEven: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto x = Round(src.Float(i)); + // dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src)); + dst.move(i, x + ((SIMD::Float(CmpLT(x, src.Float(i)) & SIMD::Int(1)) * SIMD::Float(2.0f)) - SIMD::Float(1.0f)) * + SIMD::Float(CmpEQ(Frac(src.Float(i)), SIMD::Float(0.5f)) & SIMD::Int(1)) * SIMD::Float(Int4(x) & SIMD::Int(1))); + } + break; + } + case GLSLstd450FMin: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Min(lhs.Float(i), rhs.Float(i))); + } + break; + } + case GLSLstd450FMax: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Max(lhs.Float(i), rhs.Float(i))); + } + break; + } + case GLSLstd450SMin: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Min(lhs.Int(i), rhs.Int(i))); + } + break; + } + case GLSLstd450SMax: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Max(lhs.Int(i), rhs.Int(i))); + } + break; + } + case GLSLstd450UMin: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Min(lhs.UInt(i), rhs.UInt(i))); + } + break; + } + case GLSLstd450UMax: + { + auto lhs = GenericValue(this, state, insn.word(5)); + auto rhs = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Max(lhs.UInt(i), rhs.UInt(i))); + } + break; + } + case GLSLstd450Step: + { + auto edge = GenericValue(this, state, insn.word(5)); + auto x = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f))); + } + break; + } + case GLSLstd450SmoothStep: + { + auto edge0 = GenericValue(this, state, insn.word(5)); + auto edge1 = GenericValue(this, state, insn.word(6)); + auto x = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto tx = Min(Max((x.Float(i) - edge0.Float(i)) / + (edge1.Float(i) - edge0.Float(i)), SIMD::Float(0.0f)), SIMD::Float(1.0f)); + dst.move(i, tx * tx * (Float4(3.0f) - Float4(2.0f) * tx)); + } + break; + } + case GLSLstd450FMix: + { + auto x = GenericValue(this, state, insn.word(5)); + auto y = GenericValue(this, state, insn.word(6)); + auto a = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i)); + } + break; + } + case GLSLstd450FClamp: + { + auto x = GenericValue(this, state, insn.word(5)); + auto minVal = GenericValue(this, state, insn.word(6)); + auto maxVal = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i))); + } + break; + } + case GLSLstd450SClamp: + { + auto x = GenericValue(this, state, insn.word(5)); + auto minVal = GenericValue(this, state, insn.word(6)); + auto maxVal = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i))); + } + break; + } + case GLSLstd450UClamp: + { + auto x = GenericValue(this, state, insn.word(5)); + auto minVal = GenericValue(this, state, insn.word(6)); + auto maxVal = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i))); + } + break; + } + case GLSLstd450FSign: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f)); + auto pos = As<SIMD::Int>(CmpNLE(src.Float(i), SIMD::Float(+0.0f))) & As<SIMD::Int>(SIMD::Float(1.0f)); + dst.move(i, neg | pos); + } + break; + } + case GLSLstd450SSign: + { + auto src = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1); + auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1); + dst.move(i, neg | pos); + } + break; + } + case GLSLstd450Reflect: + { + auto I = GenericValue(this, state, insn.word(5)); + auto N = GenericValue(this, state, insn.word(6)); + + SIMD::Float d = Dot(type.sizeInComponents, I, N); + + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i)); + } + break; + } + case GLSLstd450Refract: + { + auto I = GenericValue(this, state, insn.word(5)); + auto N = GenericValue(this, state, insn.word(6)); + auto eta = GenericValue(this, state, insn.word(7)); + + SIMD::Float d = Dot(type.sizeInComponents, I, N); + SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d); + SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f)); + SIMD::Float t = (eta.Float(0) * d + Sqrt(k)); + + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i))); + } + break; + } + case GLSLstd450FaceForward: + { + auto N = GenericValue(this, state, insn.word(5)); + auto I = GenericValue(this, state, insn.word(6)); + auto Nref = GenericValue(this, state, 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++) + { + auto n = N.Float(i); + dst.move(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n))); + } + break; + } + case GLSLstd450Length: + { + auto x = GenericValue(this, state, insn.word(5)); + SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x); + + dst.move(0, Sqrt(d)); + break; + } + case GLSLstd450Normalize: + { + auto x = GenericValue(this, state, 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.move(i, invLength * x.Float(i)); + } + break; + } + case GLSLstd450Distance: + { + auto p0 = GenericValue(this, state, insn.word(5)); + auto p1 = GenericValue(this, state, insn.word(6)); + auto p0Type = getType(p0.type); + + // sqrt(dot(p0-p1, p0-p1)) + SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0)); + + for (auto i = 1u; i < p0Type.sizeInComponents; i++) + { + d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i)); + } + + dst.move(0, Sqrt(d)); + break; + } + case GLSLstd450Modf: + { + auto val = GenericValue(this, state, insn.word(5)); + auto ptrId = Object::ID(insn.word(6)); + auto ptrTy = getType(getObject(ptrId).type); + auto ptr = GetPointerToData(ptrId, 0, state); + bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass); + // TODO: GLSL modf() takes an output parameter and thus the pointer is assumed + // to be in bounds even for inactive lanes. + // - Clarify the SPIR-V spec. + // - Eliminate lane masking and assume interleaving. + auto robustness = OutOfBoundsBehavior::UndefinedBehavior; + + for (auto i = 0u; i < type.sizeInComponents; i++) + { + SIMD::Float whole, frac; + std::tie(whole, frac) = Modf(val.Float(i)); + dst.move(i, frac); + auto p = ptr + (i * sizeof(float)); + if (interleavedByLane) { p = InterleaveByLane(p); } + p.Store(whole, robustness, state->activeLaneMask()); + } + break; + } + case GLSLstd450ModfStruct: + { + auto val = GenericValue(this, state, insn.word(5)); + auto valTy = getType(val.type); + + for (auto i = 0u; i < valTy.sizeInComponents; i++) + { + SIMD::Float whole, frac; + std::tie(whole, frac) = Modf(val.Float(i)); + dst.move(i, frac); + dst.move(i + valTy.sizeInComponents, whole); + } + break; + } + case GLSLstd450PackSnorm4x8: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & + SIMD::Int(0xFF)) | + ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & + SIMD::Int(0xFF)) << 8) | + ((SIMD::Int(Round(Min(Max(val.Float(2), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & + SIMD::Int(0xFF)) << 16) | + ((SIMD::Int(Round(Min(Max(val.Float(3), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(127.0f))) & + SIMD::Int(0xFF)) << 24)); + break; + } + case GLSLstd450PackUnorm4x8: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) | + ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 8) | + ((SIMD::UInt(Round(Min(Max(val.Float(2), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 16) | + ((SIMD::UInt(Round(Min(Max(val.Float(3), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(255.0f)))) << 24)); + break; + } + case GLSLstd450PackSnorm2x16: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, (SIMD::Int(Round(Min(Max(val.Float(0), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) & + SIMD::Int(0xFFFF)) | + ((SIMD::Int(Round(Min(Max(val.Float(1), SIMD::Float(-1.0f)), SIMD::Float(1.0f)) * SIMD::Float(32767.0f))) & + SIMD::Int(0xFFFF)) << 16)); + break; + } + case GLSLstd450PackUnorm2x16: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, (SIMD::UInt(Round(Min(Max(val.Float(0), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) & + SIMD::UInt(0xFFFF)) | + ((SIMD::UInt(Round(Min(Max(val.Float(1), SIMD::Float(0.0f)), SIMD::Float(1.0f)) * SIMD::Float(65535.0f))) & + SIMD::UInt(0xFFFF)) << 16)); + break; + } + case GLSLstd450PackHalf2x16: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, FloatToHalfBits(val.UInt(0), false) | FloatToHalfBits(val.UInt(1), true)); + break; + } + case GLSLstd450UnpackSnorm4x8: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, Min(Max(SIMD::Float(((val.Int(0)<<24) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); + dst.move(1, Min(Max(SIMD::Float(((val.Int(0)<<16) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); + dst.move(2, Min(Max(SIMD::Float(((val.Int(0)<<8) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); + dst.move(3, Min(Max(SIMD::Float(((val.Int(0)) & SIMD::Int(0xFF000000))) * SIMD::Float(1.0f / float(0x7f000000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); + break; + } + case GLSLstd450UnpackUnorm4x8: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); + dst.move(1, SIMD::Float(((val.UInt(0)>>8) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); + dst.move(2, SIMD::Float(((val.UInt(0)>>16) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); + dst.move(3, SIMD::Float(((val.UInt(0)>>24) & SIMD::UInt(0xFF))) * SIMD::Float(1.0f / 255.f)); + break; + } + case GLSLstd450UnpackSnorm2x16: + { + auto val = GenericValue(this, state, insn.word(5)); + // clamp(f / 32767.0, -1.0, 1.0) + dst.move(0, Min(Max(SIMD::Float(As<SIMD::Int>((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16)) * + SIMD::Float(1.0f / float(0x7FFF0000)), SIMD::Float(-1.0f)), SIMD::Float(1.0f))); + dst.move(1, Min(Max(SIMD::Float(As<SIMD::Int>(val.UInt(0) & SIMD::UInt(0xFFFF0000))) * SIMD::Float(1.0f / float(0x7FFF0000)), + SIMD::Float(-1.0f)), SIMD::Float(1.0f))); + break; + } + case GLSLstd450UnpackUnorm2x16: + { + auto val = GenericValue(this, state, insn.word(5)); + // f / 65535.0 + dst.move(0, SIMD::Float((val.UInt(0) & SIMD::UInt(0x0000FFFF)) << 16) * SIMD::Float(1.0f / float(0xFFFF0000))); + dst.move(1, SIMD::Float(val.UInt(0) & SIMD::UInt(0xFFFF0000)) * SIMD::Float(1.0f / float(0xFFFF0000))); + break; + } + case GLSLstd450UnpackHalf2x16: + { + auto val = GenericValue(this, state, insn.word(5)); + dst.move(0, halfToFloatBits(val.UInt(0) & SIMD::UInt(0x0000FFFF))); + dst.move(1, halfToFloatBits((val.UInt(0) & SIMD::UInt(0xFFFF0000)) >> 16)); + break; + } + case GLSLstd450Fma: + { + auto a = GenericValue(this, state, insn.word(5)); + auto b = GenericValue(this, state, insn.word(6)); + auto c = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, FMA(a.Float(i), b.Float(i), c.Float(i))); + } + break; + } + case GLSLstd450Frexp: + { + auto val = GenericValue(this, state, insn.word(5)); + auto ptrId = Object::ID(insn.word(6)); + auto ptrTy = getType(getObject(ptrId).type); + auto ptr = GetPointerToData(ptrId, 0, state); + bool interleavedByLane = IsStorageInterleavedByLane(ptrTy.storageClass); + // TODO: GLSL frexp() takes an output parameter and thus the pointer is assumed + // to be in bounds even for inactive lanes. + // - Clarify the SPIR-V spec. + // - Eliminate lane masking and assume interleaving. + auto robustness = OutOfBoundsBehavior::UndefinedBehavior; + + for (auto i = 0u; i < type.sizeInComponents; i++) + { + SIMD::Float significand; + SIMD::Int exponent; + std::tie(significand, exponent) = Frexp(val.Float(i)); + + dst.move(i, significand); + + auto p = ptr + (i * sizeof(float)); + if (interleavedByLane) { p = InterleaveByLane(p); } + p.Store(exponent, robustness, state->activeLaneMask()); + } + break; + } + case GLSLstd450FrexpStruct: + { + auto val = GenericValue(this, state, insn.word(5)); + auto numComponents = getType(val.type).sizeInComponents; + for (auto i = 0u; i < numComponents; i++) + { + auto significandAndExponent = Frexp(val.Float(i)); + dst.move(i, significandAndExponent.first); + dst.move(i + numComponents, significandAndExponent.second); + } + break; + } + case GLSLstd450Ldexp: + { + auto significand = GenericValue(this, state, insn.word(5)); + auto exponent = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + // Assumes IEEE 754 + auto in = significand.Float(i); + auto significandExponent = Exponent(in); + auto combinedExponent = exponent.Int(i) + significandExponent; + auto isSignificandZero = SIMD::UInt(CmpEQ(significand.Int(i), SIMD::Int(0))); + auto isSignificandInf = SIMD::UInt(IsInf(in)); + auto isSignificandNaN = SIMD::UInt(IsNan(in)); + auto isExponentNotTooSmall = SIMD::UInt(CmpGE(combinedExponent, SIMD::Int(-126))); + auto isExponentNotTooLarge = SIMD::UInt(CmpLE(combinedExponent, SIMD::Int(128))); + auto isExponentInBounds = isExponentNotTooSmall & isExponentNotTooLarge; + + SIMD::UInt v; + v = significand.UInt(i) & SIMD::UInt(0x7FFFFF); // Add significand. + v |= (SIMD::UInt(combinedExponent + SIMD::Int(126)) << SIMD::UInt(23)); // Add exponent. + v &= isExponentInBounds; // Clear v if the exponent is OOB. + + v |= significand.UInt(i) & SIMD::UInt(0x80000000); // Add sign bit. + v |= ~isExponentNotTooLarge & SIMD::UInt(0x7F800000); // Mark as inf if the exponent is too great. + + // If the input significand is zero, inf or nan, just return the + // input significand. + auto passthrough = isSignificandZero | isSignificandInf | isSignificandNaN; + v = (v & ~passthrough) | (significand.UInt(i) & passthrough); + + dst.move(i, As<SIMD::Float>(v)); + } + break; + } + case GLSLstd450Radians: + { + auto degrees = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, degrees.Float(i) * SIMD::Float(PI / 180.0f)); + } + break; + } + case GLSLstd450Degrees: + { + auto radians = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, radians.Float(i) * SIMD::Float(180.0f / PI)); + } + break; + } + case GLSLstd450Sin: + { + auto radians = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Sin(radians.Float(i))); + } + break; + } + case GLSLstd450Cos: + { + auto radians = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Cos(radians.Float(i))); + } + break; + } + case GLSLstd450Tan: + { + auto radians = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Tan(radians.Float(i))); + } + break; + } + case GLSLstd450Asin: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Asin(val.Float(i))); + } + break; + } + case GLSLstd450Acos: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Acos(val.Float(i))); + } + break; + } + case GLSLstd450Atan: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Atan(val.Float(i))); + } + break; + } + case GLSLstd450Sinh: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Sinh(val.Float(i))); + } + break; + } + case GLSLstd450Cosh: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Cosh(val.Float(i))); + } + break; + } + case GLSLstd450Tanh: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Tanh(val.Float(i))); + } + break; + } + case GLSLstd450Asinh: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Asinh(val.Float(i))); + } + break; + } + case GLSLstd450Acosh: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Acosh(val.Float(i))); + } + break; + } + case GLSLstd450Atanh: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Atanh(val.Float(i))); + } + break; + } + case GLSLstd450Atan2: + { + auto x = GenericValue(this, state, insn.word(5)); + auto y = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Atan2(x.Float(i), y.Float(i))); + } + break; + } + case GLSLstd450Pow: + { + auto x = GenericValue(this, state, insn.word(5)); + auto y = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Pow(x.Float(i), y.Float(i))); + } + break; + } + case GLSLstd450Exp: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Exp(val.Float(i))); + } + break; + } + case GLSLstd450Log: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Log(val.Float(i))); + } + break; + } + case GLSLstd450Exp2: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Exp2(val.Float(i))); + } + break; + } + case GLSLstd450Log2: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Log2(val.Float(i))); + } + break; + } + case GLSLstd450Sqrt: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, Sqrt(val.Float(i))); + } + break; + } + case GLSLstd450InverseSqrt: + { + auto val = GenericValue(this, state, insn.word(5)); + Decorations d; + ApplyDecorationsForId(&d, insn.word(5)); + if (d.RelaxedPrecision) + { + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, RcpSqrt_pp(val.Float(i))); + } + } + else + { + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, SIMD::Float(1.0f) / Sqrt(val.Float(i))); + } + } + break; + } + case GLSLstd450Determinant: + { + auto mat = GenericValue(this, state, insn.word(5)); + auto numComponents = getType(mat.type).sizeInComponents; + switch (numComponents) + { + case 4: // 2x2 + dst.move(0, Determinant( + mat.Float(0), mat.Float(1), + mat.Float(2), mat.Float(3))); + break; + case 9: // 3x3 + dst.move(0, Determinant( + mat.Float(0), mat.Float(1), mat.Float(2), + mat.Float(3), mat.Float(4), mat.Float(5), + mat.Float(6), mat.Float(7), mat.Float(8))); + break; + case 16: // 4x4 + dst.move(0, Determinant( + mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3), + mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7), + mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11), + mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15))); + break; + default: + UNREACHABLE("GLSLstd450Determinant can only operate with square matrices. Got %d elements", int(numComponents)); + } + break; + } + case GLSLstd450MatrixInverse: + { + auto mat = GenericValue(this, state, insn.word(5)); + auto numComponents = getType(mat.type).sizeInComponents; + switch (numComponents) + { + case 4: // 2x2 + { + auto inv = MatrixInverse( + mat.Float(0), mat.Float(1), + mat.Float(2), mat.Float(3)); + for (uint32_t i = 0; i < inv.size(); i++) + { + dst.move(i, inv[i]); + } + break; + } + case 9: // 3x3 + { + auto inv = MatrixInverse( + mat.Float(0), mat.Float(1), mat.Float(2), + mat.Float(3), mat.Float(4), mat.Float(5), + mat.Float(6), mat.Float(7), mat.Float(8)); + for (uint32_t i = 0; i < inv.size(); i++) + { + dst.move(i, inv[i]); + } + break; + } + case 16: // 4x4 + { + auto inv = MatrixInverse( + mat.Float(0), mat.Float(1), mat.Float(2), mat.Float(3), + mat.Float(4), mat.Float(5), mat.Float(6), mat.Float(7), + mat.Float(8), mat.Float(9), mat.Float(10), mat.Float(11), + mat.Float(12), mat.Float(13), mat.Float(14), mat.Float(15)); + for (uint32_t i = 0; i < inv.size(); i++) + { + dst.move(i, inv[i]); + } + break; + } + default: + UNREACHABLE("GLSLstd450MatrixInverse can only operate with square matrices. Got %d elements", int(numComponents)); + } + break; + } + case GLSLstd450IMix: + { + UNREACHABLE("GLSLstd450IMix has been removed from the specification"); + break; + } + case GLSLstd450PackDouble2x32: + { + UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450PackDouble2x32)"); + break; + } + case GLSLstd450UnpackDouble2x32: + { + UNSUPPORTED("SPIR-V Float64 Capability (GLSLstd450UnpackDouble2x32)"); + break; + } + case GLSLstd450FindILsb: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto v = val.UInt(i); + dst.move(i, Cttz(v, true) | CmpEQ(v, SIMD::UInt(0))); + } + break; + } + case GLSLstd450FindSMsb: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto v = val.UInt(i) ^ As<SIMD::UInt>(CmpLT(val.Int(i), SIMD::Int(0))); + dst.move(i, SIMD::UInt(31) - Ctlz(v, false)); + } + break; + } + case GLSLstd450FindUMsb: + { + auto val = GenericValue(this, state, insn.word(5)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, SIMD::UInt(31) - Ctlz(val.UInt(i), false)); + } + break; + } + case GLSLstd450InterpolateAtCentroid: + { + UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); + break; + } + case GLSLstd450InterpolateAtSample: + { + UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); + break; + } + case GLSLstd450InterpolateAtOffset: + { + UNSUPPORTED("SPIR-V SampleRateShading Capability (GLSLstd450InterpolateAtCentroid)"); + break; + } + case GLSLstd450NMin: + { + auto x = GenericValue(this, state, insn.word(5)); + auto y = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, NMin(x.Float(i), y.Float(i))); + } + break; + } + case GLSLstd450NMax: + { + auto x = GenericValue(this, state, insn.word(5)); + auto y = GenericValue(this, state, insn.word(6)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + dst.move(i, NMax(x.Float(i), y.Float(i))); + } + break; + } + case GLSLstd450NClamp: + { + auto x = GenericValue(this, state, insn.word(5)); + auto minVal = GenericValue(this, state, insn.word(6)); + auto maxVal = GenericValue(this, state, insn.word(7)); + for (auto i = 0u; i < type.sizeInComponents; i++) + { + auto clamp = NMin(NMax(x.Float(i), minVal.Float(i)), maxVal.Float(i)); + dst.move(i, clamp); + } + break; + } + default: + UNREACHABLE("ExtInst %d", int(extInstIndex)); + break; + } + + return EmitResult::Continue; +} + +} // namespace sw \ No newline at end of file
diff --git a/src/Vulkan/vulkan.vcxproj b/src/Vulkan/vulkan.vcxproj index 7ee6982..3b6c30e 100644 --- a/src/Vulkan/vulkan.vcxproj +++ b/src/Vulkan/vulkan.vcxproj
@@ -165,6 +165,7 @@ <ClCompile Include="..\Pipeline\SetupRoutine.cpp" /> <ClCompile Include="..\Pipeline\ShaderCore.cpp" /> <ClCompile Include="..\Pipeline\SpirvShader.cpp" /> + <ClCompile Include="..\Pipeline\SpirvShaderGLSLstd450.cpp" /> <ClCompile Include="..\Pipeline\SpirvShaderSampling.cpp" /> <ClCompile Include="..\Pipeline\SpirvShader_dbg.cpp" /> <ClCompile Include="..\Pipeline\VertexProgram.cpp" />
diff --git a/src/Vulkan/vulkan.vcxproj.filters b/src/Vulkan/vulkan.vcxproj.filters index 34ed4c7..7a0e176 100644 --- a/src/Vulkan/vulkan.vcxproj.filters +++ b/src/Vulkan/vulkan.vcxproj.filters
@@ -246,6 +246,9 @@ <ClCompile Include="..\Pipeline\SpirvShader.cpp"> <Filter>Source Files\Pipeline</Filter> </ClCompile> + <ClCompile Include="..\Pipeline\SpirvShaderGLSLstd450.cpp"> + <Filter>Source Files\Pipeline</Filter> + </ClCompile> <ClCompile Include="..\Pipeline\SpirvShaderSampling.cpp"> <Filter>Source Files\Pipeline</Filter> </ClCompile>