blob: f6aaeca5f51d5e40cc6c54a61078f6abb5001d22 [file] [log] [blame]
// 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/GLSL.std.450.h>
#include <spirv/unified1/spirv.hpp>
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