Files
renderdoc/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp
T
baldurk cef00a102b Add struct VarType and combine flags into single field
* This is not a space saving right now, but allows more flags to be added
  without adding more storage.
2022-05-20 13:37:25 +01:00

1343 lines
32 KiB
C++

/******************************************************************************
* The MIT License (MIT)
*
* Copyright (c) 2020-2022 Baldur Karlsson
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
#include "spirv_debug.h"
#include <math.h>
#include "maths/half_convert.h"
#include "maths/matrix.h"
#include "os/os_specific.h"
#include "var_dispatch_helpers.h"
// add some overloads we'll use to avoid the mess of math function definitions across compilers and
// C/C++
inline int8_t RDCABS(int8_t v)
{
return v < 0 ? -v : v;
}
inline int16_t RDCABS(int16_t v)
{
return v < 0 ? -v : v;
}
inline int32_t RDCABS(int32_t v)
{
return v < 0 ? -v : v;
}
inline int64_t RDCABS(int64_t v)
{
return v < 0 ? -v : v;
}
inline float RDCMODF(float a, float *b)
{
return modff(a, b);
}
inline double RDCMODF(double a, double *b)
{
return modf(a, b);
}
inline half_float::half RDCMODF(half_float::half a, half_float::half *b)
{
return half_float::modf(a, b);
}
namespace rdcspv
{
namespace glsl
{
#define CHECK_PARAMS(n) \
if(params.size() != n) \
{ \
RDCERR("Unexpected number of parameters (%zu) to %s, expected %u", params.size(), \
__PRETTY_FUNCTION_SIGNATURE__, n); \
return ShaderVariable(); \
}
ShaderVariable RoundEven(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
T x = comp<T>(var, c); \
if(RDCISFINITE(x)) \
comp<T>(var, c) = x - remainder(x, (T)1.0);
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Round(ThreadState &state, uint32_t instruction, const rdcarray<Id> &params)
{
// for now do as the spec allows and implement this as RoundEven
return RoundEven(state, instruction, params);
}
ShaderVariable Trunc(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = trunc(comp<T>(var, c))
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable FAbs(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = fabs(comp<T>(var, c))
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable SAbs(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) comp<S>(var, c) = RDCABS(comp<S>(var, c))
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable FSign(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
T val = comp<T>(var, c); \
if(val > 0.0) \
comp<T>(var, c) = 1.0; \
else if(val < 0.0) \
comp<T>(var, c) = -1.0;
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable SSign(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) \
S val = comp<S>(var, c); \
if(val > 0) \
comp<S>(var, c) = 1; \
else if(val < 0) \
comp<S>(var, c) = -1;
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Floor(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = floor(comp<T>(var, c))
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Ceil(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = ceil(comp<T>(var, c))
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Fract(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = comp<T>(var, c) - floor(comp<T>(var, c))
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
static const float piOver180 = 3.14159265358979323846f / 180.0f;
static const float piUnder180 = 180.0f / 3.14159265358979323846f;
ShaderVariable Radians(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = comp<T>(var, c) * piOver180;
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Degrees(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = comp<T>(var, c) * piUnder180;
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Determinant(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable m = var;
if(var.type != VarType::Float)
{
static bool warned = false;
if(!warned)
{
warned = true;
RDCLOG("Calculating determinant at float precision instead of %s", ToStr(m.type).c_str());
}
for(uint8_t c = 0; c < m.rows * m.columns; c++)
m.value.f32v[c] = floatComp(var, c);
}
RDCASSERTEQUAL(m.rows, m.columns);
if(m.rows == 4)
{
Matrix4f mat;
mat.SetFrom(m.value.f32v.data());
m.value.f32v[0] = mat.Determinant();
}
else if(m.rows == 3)
{
Matrix3f mat;
mat.SetFrom(m.value.f32v.data());
m.value.f32v[0] = mat.Determinant();
}
else if(m.rows == 2)
{
Matrix2f mat;
mat.SetFrom(m.value.f32v.data());
m.value.f32v[0] = mat.Determinant();
}
m.rows = m.columns = 1;
if(var.type != VarType::Float)
{
float f = m.value.f32v[0];
setFloatComp(m, 0, f);
}
return m;
}
ShaderVariable MatrixInverse(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable m = var;
if(var.type != VarType::Float)
{
static bool warned = false;
if(!warned)
{
warned = true;
RDCLOG("Calculating matrix inverse at float precision instead of %s", ToStr(m.type).c_str());
}
for(uint8_t c = 0; c < m.rows * m.columns; c++)
m.value.f32v[c] = floatComp(var, c);
}
RDCASSERTEQUAL(m.rows, m.columns);
if(m.rows == 4)
{
Matrix4f mat;
mat.SetFrom(m.value.f32v.data());
memcpy(m.value.f32v.data(), mat.Inverse().Data(), sizeof(mat));
}
else if(m.rows == 3)
{
Matrix3f mat;
mat.SetFrom(m.value.f32v.data());
memcpy(m.value.f32v.data(), mat.Inverse().Data(), sizeof(mat));
}
else if(m.rows == 2)
{
Matrix2f mat;
mat.SetFrom(m.value.f32v.data());
memcpy(m.value.f32v.data(), mat.Inverse().Data(), sizeof(mat));
}
if(var.type != VarType::Float)
{
var = m;
for(uint8_t c = 0; c < m.rows * m.columns; c++)
setFloatComp(m, c, var.value.f32v[c]);
}
return m;
}
ShaderVariable Modf(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
Id iptr = params[1];
ShaderVariable whole = var;
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = RDCMODF(comp<T>(var, c), &comp<T>(whole, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
state.WritePointerValue(iptr, whole);
return var;
}
ShaderVariable ModfStruct(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable ret;
ret.rows = 1;
ret.columns = 1;
ret.type = VarType::Struct;
ret.members = {var, var};
ret.members[0].name = "_child0";
ret.members[1].name = "_child1";
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(ret.members[0], c) = RDCMODF(comp<T>(var, c), &comp<T>(ret.members[1], c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return ret;
}
template <typename T>
static T GLSLMax(T x, T y)
{
return x < y ? y : x;
}
template <typename T>
static T GLSLMin(T x, T y)
{
return y < x ? y : x;
}
template <>
float GLSLMax(float x, float y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return x < y ? y : x;
}
template <>
float GLSLMin(float x, float y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return y < x ? y : x;
}
template <>
double GLSLMax(double x, double y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return x < y ? y : x;
}
template <>
double GLSLMin(double x, double y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return y < x ? y : x;
}
template <>
half_float::half GLSLMax(half_float::half x, half_float::half y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return x < y ? y : x;
}
template <>
half_float::half GLSLMin(half_float::half x, half_float::half y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return y < x ? y : x;
}
ShaderVariable FMax(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = GLSLMax(comp<T>(var, c), comp<T>(y, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable UMax(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) comp<U>(var, c) = GLSLMax(comp<U>(var, c), comp<U>(y, c));
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable SMax(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) comp<S>(var, c) = GLSLMax(comp<S>(var, c), comp<S>(y, c));
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable FMin(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = GLSLMin(comp<T>(var, c), comp<T>(y, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable UMin(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) comp<U>(var, c) = GLSLMin(comp<U>(var, c), comp<U>(y, c));
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable SMin(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) comp<S>(var, c) = GLSLMin(comp<S>(var, c), comp<S>(y, c));
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable FClamp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable minVal = state.GetSrc(params[1]);
ShaderVariable maxVal = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
comp<T>(var, c) = GLSLMin(GLSLMax(comp<T>(var, c), comp<T>(minVal, c)), comp<T>(maxVal, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable UClamp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable minVal = state.GetSrc(params[1]);
ShaderVariable maxVal = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) \
comp<U>(var, c) = GLSLMin(GLSLMax(comp<U>(var, c), comp<U>(minVal, c)), comp<U>(maxVal, c));
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable SClamp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable minVal = state.GetSrc(params[1]);
ShaderVariable maxVal = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(I, S, U) \
comp<S>(var, c) = GLSLMin(GLSLMax(comp<S>(var, c), comp<S>(minVal, c)), comp<S>(maxVal, c));
IMPL_FOR_INT_TYPES(_IMPL);
}
return var;
}
ShaderVariable FMix(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
ShaderVariable a = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
T xf = comp<T>(var, c); \
T yf = comp<T>(y, c); \
T af = comp<T>(a, c); \
\
comp<T>(var, c) = xf * (1 - af) + yf * af;
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Step(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable edge = state.GetSrc(params[0]);
ShaderVariable var = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = comp<T>(var, c) < comp<T>(edge, c) ? T(0.0) : T(1.0);
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable SmoothStep(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable edge0 = state.GetSrc(params[0]);
ShaderVariable edge1 = state.GetSrc(params[1]);
ShaderVariable var = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
T edge0f = comp<T>(edge0, c); \
T edge1f = comp<T>(edge1, c); \
T xf = comp<T>(var, c); \
\
T t = GLSLMin(GLSLMax((xf - edge0f) / (edge1f - edge0f), T(0.0)), T(1.0)); \
\
comp<T>(var, c) = t * t * (T(3.0) - T(2.0) * t);
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable Frexp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
Id iptr = params[1];
ShaderVariable whole = var;
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = frexp(comp<T>(var, c), &comp<int32_t>(whole, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
state.WritePointerValue(iptr, whole);
return var;
}
ShaderVariable FrexpStruct(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable ret;
ret.rows = 1;
ret.columns = 1;
ret.type = VarType::Struct;
ret.members = {var, var};
ret.members[0].name = "_child0";
ret.members[1].name = "_child1";
// member 1 must be a scalar or vector with integer type, and 32-bit width
ret.members[1].type = VarType::SInt;
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
comp<T>(ret.members[0], c) = frexp(comp<T>(var, c), &comp<int32_t>(ret.members[1], c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return ret;
}
ShaderVariable Ldexp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable exp = state.GetSrc(params[1]);
for(uint8_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = ldexp(comp<T>(var, c), comp<int32_t>(exp, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable PackSnorm4x8(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = 0;
// The v operand must be a vector of 4 components whose type is a 32-bit floating-point.
packed |= (int32_t(RDCCLAMP(v.value.f32v[0], -1.0f, 1.0f) * 127.0f) & 0xff) << 0;
packed |= (int32_t(RDCCLAMP(v.value.f32v[1], -1.0f, 1.0f) * 127.0f) & 0xff) << 8;
packed |= (int32_t(RDCCLAMP(v.value.f32v[2], -1.0f, 1.0f) * 127.0f) & 0xff) << 16;
packed |= (int32_t(RDCCLAMP(v.value.f32v[3], -1.0f, 1.0f) * 127.0f) & 0xff) << 24;
v.value.u32v[0] = packed;
v.type = VarType::UInt;
v.columns = 1;
return v;
}
ShaderVariable PackUnorm4x8(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = 0;
// The v operand must be a vector of 4 components whose type is a 32-bit floating-point.
packed |= (uint32_t(RDCCLAMP(v.value.f32v[0], 0.0f, 1.0f) * 255.0f) & 0xff) << 0;
packed |= (uint32_t(RDCCLAMP(v.value.f32v[1], 0.0f, 1.0f) * 255.0f) & 0xff) << 8;
packed |= (uint32_t(RDCCLAMP(v.value.f32v[2], 0.0f, 1.0f) * 255.0f) & 0xff) << 16;
packed |= (uint32_t(RDCCLAMP(v.value.f32v[3], 0.0f, 1.0f) * 255.0f) & 0xff) << 24;
v.value.u32v[0] = packed;
v.type = VarType::UInt;
v.columns = 1;
return v;
}
ShaderVariable PackSnorm2x16(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = 0;
// The v operand must be a vector of 4 components whose type is a 32-bit floating-point.
packed |= (int32_t(RDCCLAMP(v.value.f32v[0], -1.0f, 1.0f) * 32767.0f) & 0xffff) << 0;
packed |= (int32_t(RDCCLAMP(v.value.f32v[1], -1.0f, 1.0f) * 32767.0f) & 0xffff) << 16;
v.value.u32v[0] = packed;
v.type = VarType::UInt;
v.columns = 1;
return v;
}
ShaderVariable PackUnorm2x16(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = 0;
// The v operand must be a vector of 4 components whose type is a 32-bit floating-point.
packed |= (uint32_t(RDCCLAMP(v.value.f32v[0], 0.0f, 1.0f) * 65535.0f) & 0xffff) << 0;
packed |= (uint32_t(RDCCLAMP(v.value.f32v[1], 0.0f, 1.0f) * 65535.0f) & 0xffff) << 16;
v.value.u32v[0] = packed;
v.type = VarType::UInt;
v.columns = 1;
return v;
}
ShaderVariable PackHalf2x16(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = 0;
// The v operand must be a vector of 4 components whose type is a 32-bit floating-point.
packed |= ConvertToHalf(v.value.f32v[0]) << 0;
packed |= ConvertToHalf(v.value.f32v[1]) << 16;
v.value.u32v[0] = packed;
v.type = VarType::UInt;
v.columns = 1;
return v;
}
ShaderVariable PackDouble2x32(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
// u64 is aliased with the double, so we just OR together
v.value.u64v[0] = uint64_t(v.value.u32v[0]) | (uint64_t(v.value.u32v[1]) << 32);
v.type = VarType::Double;
v.columns = 1;
return v;
}
ShaderVariable UnpackSnorm4x8(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = v.value.u32v[0];
// The v operand must be a vector of 4 components whose type is a 32-bit floating-point.
v.value.f32v[0] = RDCCLAMP(float(int8_t((packed >> 0) & 0xff)) / 127.0f, -1.0f, 1.0f);
v.value.f32v[1] = RDCCLAMP(float(int8_t((packed >> 8) & 0xff)) / 127.0f, -1.0f, 1.0f);
v.value.f32v[2] = RDCCLAMP(float(int8_t((packed >> 16) & 0xff)) / 127.0f, -1.0f, 1.0f);
v.value.f32v[3] = RDCCLAMP(float(int8_t((packed >> 24) & 0xff)) / 127.0f, -1.0f, 1.0f);
v.type = VarType::Float;
v.columns = 4;
return v;
}
ShaderVariable UnpackUnorm4x8(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = v.value.u32v[0];
v.value.f32v[0] = float((packed >> 0) & 0xff) / 255.0f;
v.value.f32v[1] = float((packed >> 8) & 0xff) / 255.0f;
v.value.f32v[2] = float((packed >> 16) & 0xff) / 255.0f;
v.value.f32v[3] = float((packed >> 24) & 0xff) / 255.0f;
v.type = VarType::Float;
v.columns = 4;
return v;
}
ShaderVariable UnpackSnorm2x16(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = v.value.u32v[0];
v.value.f32v[0] = RDCCLAMP(float(int16_t((packed >> 0) & 0xffff)) / 32767.0f, -1.0f, 1.0f);
v.value.f32v[1] = RDCCLAMP(float(int16_t((packed >> 16) & 0xffff)) / 32767.0f, -1.0f, 1.0f);
v.type = VarType::Float;
v.columns = 2;
return v;
}
ShaderVariable UnpackUnorm2x16(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = v.value.u32v[0];
v.value.f32v[0] = float((packed >> 0) & 0xffff) / 65535.0f;
v.value.f32v[1] = float((packed >> 16) & 0xffff) / 65535.0f;
v.type = VarType::Float;
v.columns = 2;
return v;
}
ShaderVariable UnpackHalf2x16(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
uint32_t packed = v.value.u32v[0];
v.value.f32v[0] = ConvertFromHalf((packed >> 0) & 0xffff);
v.value.f32v[1] = ConvertFromHalf((packed >> 16) & 0xffff);
v.type = VarType::Float;
v.columns = 2;
return v;
}
ShaderVariable UnpackDouble2x32(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable v = state.GetSrc(params[0]);
// u64 is aliased with the double, so we just OR together
uint64_t doubleUint = v.value.u64v[0];
v.value.u32v[0] = (doubleUint >> 0) & 0xFFFFFFFFU;
v.value.u32v[1] = (doubleUint >> 32) & 0xFFFFFFFFU;
v.type = VarType::UInt;
v.columns = 2;
return v;
}
ShaderVariable Cross(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable x = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
RDCASSERT(x.columns == 3 && y.columns == 3, x.columns, y.columns);
ShaderVariable var = x;
#undef _IMPL
#define _IMPL(T) \
comp<T>(var, 0) = comp<T>(x, 1) * comp<T>(y, 2) - comp<T>(y, 1) * comp<T>(x, 2); \
comp<T>(var, 1) = comp<T>(x, 2) * comp<T>(y, 0) - comp<T>(y, 2) * comp<T>(x, 0); \
comp<T>(var, 2) = comp<T>(x, 0) * comp<T>(y, 1) - comp<T>(y, 0) * comp<T>(x, 1);
IMPL_FOR_FLOAT_TYPES(_IMPL);
return var;
}
ShaderVariable FaceForward(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable N = state.GetSrc(params[0]);
ShaderVariable I = state.GetSrc(params[1]);
ShaderVariable Nref = state.GetSrc(params[2]);
ShaderVariable var = N;
#undef _IMPL
#define _IMPL(T) \
T dot(0.0); \
for(uint8_t c = 0; c < var.columns; c++) \
dot += comp<T>(Nref, c) * comp<T>(I, c); \
if(dot >= 0.0) \
{ \
for(uint8_t c = 0; c < var.columns; c++) \
comp<T>(var, c) = -comp<T>(N, c); \
}
IMPL_FOR_FLOAT_TYPES(_IMPL);
return var;
}
ShaderVariable Reflect(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable I = state.GetSrc(params[0]);
ShaderVariable N = state.GetSrc(params[1]);
ShaderVariable var = N;
#undef _IMPL
#define _IMPL(T) \
T dot(0.0); \
for(uint8_t c = 0; c < var.columns; c++) \
dot += comp<T>(N, c) * comp<T>(I, c); \
\
for(uint8_t c = 0; c < var.columns; c++) \
comp<T>(var, c) = comp<T>(I, c) - T(2.0) * dot * comp<T>(N, c);
IMPL_FOR_FLOAT_TYPES(_IMPL);
return var;
}
ShaderVariable FindILsb(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable x = state.GetSrc(params[0]);
// This instruction is currently limited to 32-bit width components.
for(uint8_t c = 0; c < x.columns; c++)
x.value.s32v[c] = x.value.u32v[c] == 0 ? -1 : Bits::CountTrailingZeroes(x.value.u32v[c]);
return x;
}
ShaderVariable FindSMsb(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable x = state.GetSrc(params[0]);
// This instruction is currently limited to 32-bit width components.
for(uint8_t c = 0; c < x.columns; c++)
{
if(x.value.s32v[c] == 0 || x.value.s32v[c] == -1)
x.value.s32v[c] = -1;
else if(x.value.s32v[c] >= 0)
x.value.u32v[c] = 31 - Bits::CountLeadingZeroes(x.value.u32v[c]);
else
x.value.u32v[c] = 31 - Bits::CountLeadingZeroes(~x.value.u32v[c]);
}
return x;
}
ShaderVariable FindUMsb(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(1);
ShaderVariable x = state.GetSrc(params[0]);
// This instruction is currently limited to 32-bit width components.
for(uint8_t c = 0; c < x.columns; c++)
{
x.value.s32v[c] = x.value.s32v[c] == 0 ? -1 : 31 - Bits::CountLeadingZeroes(x.value.u32v[c]);
}
return x;
}
ShaderVariable NMin(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = GLSLMin(comp<T>(var, c), comp<T>(y, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable NMax(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) comp<T>(var, c) = GLSLMax(comp<T>(var, c), comp<T>(y, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable NClamp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(3);
ShaderVariable var = state.GetSrc(params[0]);
ShaderVariable minVal = state.GetSrc(params[1]);
ShaderVariable maxVal = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
{
#undef _IMPL
#define _IMPL(T) \
comp<T>(var, c) = GLSLMin(GLSLMax(comp<T>(var, c), comp<T>(minVal, c)), comp<T>(maxVal, c));
IMPL_FOR_FLOAT_TYPES(_IMPL);
}
return var;
}
ShaderVariable GPUOp(ThreadState &state, uint32_t instruction, const rdcarray<Id> &params)
{
rdcarray<ShaderVariable> paramVars;
for(Id id : params)
paramVars.push_back(state.GetSrc(id));
ShaderVariable ret = paramVars[0];
if(!state.debugger.GetAPIWrapper()->CalculateMathOp(state, (GLSLstd450)instruction, paramVars, ret))
memset(&ret.value, 0, sizeof(ret.value));
return ret;
}
}; // namespace glsl
void ConfigureGLSLStd450(ExtInstDispatcher &extinst)
{
extinst.names.resize((size_t)GLSLstd450::Max);
for(size_t i = 0; i < extinst.names.size(); i++)
extinst.names[i] = ToStr(GLSLstd450(i));
extinst.functions.resize(extinst.names.size());
#define EXT(func) \
extinst.functions[(uint32_t)GLSLstd450::func] = &glsl::func; \
uint32_t noduplicate##func; \
(void)noduplicate##func;
EXT(Round);
EXT(RoundEven);
EXT(Trunc);
EXT(FAbs);
EXT(SAbs);
EXT(FSign);
EXT(SSign);
EXT(Floor);
EXT(Ceil);
EXT(Fract);
EXT(Radians);
EXT(Degrees);
EXT(Determinant);
EXT(MatrixInverse);
EXT(Modf);
EXT(ModfStruct);
EXT(FMin);
EXT(UMin);
EXT(SMin);
EXT(FMax);
EXT(UMax);
EXT(SMax);
EXT(FClamp);
EXT(UClamp);
EXT(SClamp);
EXT(FMix);
EXT(Step);
EXT(SmoothStep);
EXT(Frexp);
EXT(FrexpStruct);
EXT(Ldexp);
EXT(PackSnorm4x8);
EXT(PackUnorm4x8);
EXT(PackSnorm2x16);
EXT(PackUnorm2x16);
EXT(PackHalf2x16);
EXT(PackDouble2x32);
EXT(UnpackSnorm2x16);
EXT(UnpackUnorm2x16);
EXT(UnpackHalf2x16);
EXT(UnpackSnorm4x8);
EXT(UnpackUnorm4x8);
EXT(UnpackDouble2x32);
EXT(Cross);
EXT(FaceForward);
EXT(Reflect);
EXT(FindILsb);
EXT(FindSMsb);
EXT(FindUMsb);
EXT(NMin);
EXT(NMax);
EXT(NClamp);
// transcendentals and other operations that will likely be less accurate on GPU we run on the GPU
// to be more faithful to the real execution
#define GPU_EXT(func) \
extinst.functions[(uint32_t)GLSLstd450::func] = &glsl::GPUOp; \
uint32_t noduplicate##func; \
(void)noduplicate##func;
GPU_EXT(Sin)
GPU_EXT(Cos)
GPU_EXT(Tan)
GPU_EXT(Asin)
GPU_EXT(Acos)
GPU_EXT(Atan)
GPU_EXT(Sinh)
GPU_EXT(Cosh)
GPU_EXT(Tanh)
GPU_EXT(Asinh)
GPU_EXT(Acosh)
GPU_EXT(Atanh)
GPU_EXT(Atan2)
GPU_EXT(Pow)
GPU_EXT(Exp)
GPU_EXT(Log)
GPU_EXT(Exp2)
GPU_EXT(Log2)
GPU_EXT(Sqrt)
GPU_EXT(InverseSqrt)
GPU_EXT(Fma)
GPU_EXT(Length);
GPU_EXT(Distance);
GPU_EXT(Normalize);
GPU_EXT(Refract);
}
}; // namespace rdcspv