Duckstation/dep/reshadefx/src/effect_symbol_table_intrinsics.inl
2024-09-09 00:43:32 +10:00

4504 lines
170 KiB
C++

/*
* Copyright (C) 2014 Patrick Mours
* SPDX-License-Identifier: BSD-3-Clause
*/
#if defined(__INTELLISENSE__) || !defined(DEFINE_INTRINSIC)
#define DEFINE_INTRINSIC(name, i, ret_type, ...)
#endif
#if defined(__INTELLISENSE__) || !defined(IMPLEMENT_INTRINSIC_GLSL)
#define IMPLEMENT_INTRINSIC_GLSL(name, i, code)
#endif
#if defined(__INTELLISENSE__) || !defined(IMPLEMENT_INTRINSIC_HLSL)
#define IMPLEMENT_INTRINSIC_HLSL(name, i, code)
#endif
#if defined(__INTELLISENSE__) || !defined(IMPLEMENT_INTRINSIC_SPIRV)
#define IMPLEMENT_INTRINSIC_SPIRV(name, i, code)
#endif
// ret abs(x)
DEFINE_INTRINSIC(abs, 0, int, int)
DEFINE_INTRINSIC(abs, 0, int2, int2)
DEFINE_INTRINSIC(abs, 0, int3, int3)
DEFINE_INTRINSIC(abs, 0, int4, int4)
DEFINE_INTRINSIC(abs, 1, float, float)
DEFINE_INTRINSIC(abs, 1, float2, float2)
DEFINE_INTRINSIC(abs, 1, float3, float3)
DEFINE_INTRINSIC(abs, 1, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(abs, 0, {
code += "abs(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(abs, 1, {
code += "abs(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(abs, 0, {
code += "abs(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(abs, 1, {
code += "abs(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(abs, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450SAbs)
.add(args[0].base);
})
IMPLEMENT_INTRINSIC_SPIRV(abs, 1, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FAbs)
.add(args[0].base);
})
// ret all(x)
DEFINE_INTRINSIC(all, 0, bool, bool)
DEFINE_INTRINSIC(all, 1, bool, bool2)
DEFINE_INTRINSIC(all, 1, bool, bool3)
DEFINE_INTRINSIC(all, 1, bool, bool4)
IMPLEMENT_INTRINSIC_GLSL(all, 0, {
code += id_to_name(args[0].base);
})
IMPLEMENT_INTRINSIC_GLSL(all, 1, {
code += "all(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(all, 0, {
code += id_to_name(args[0].base);
})
IMPLEMENT_INTRINSIC_HLSL(all, 1, {
code += "all(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(all, 0, {
return args[0].base;
})
IMPLEMENT_INTRINSIC_SPIRV(all, 1, {
return
add_instruction(spv::OpAll, convert_type(res_type))
.add(args[0].base);
})
// ret any(x)
DEFINE_INTRINSIC(any, 0, bool, bool)
DEFINE_INTRINSIC(any, 1, bool, bool2)
DEFINE_INTRINSIC(any, 1, bool, bool3)
DEFINE_INTRINSIC(any, 1, bool, bool4)
IMPLEMENT_INTRINSIC_GLSL(any, 0, {
code += id_to_name(args[0].base);
})
IMPLEMENT_INTRINSIC_GLSL(any, 1, {
code += "any(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(any, 0, {
code += id_to_name(args[0].base);
})
IMPLEMENT_INTRINSIC_HLSL(any, 1, {
code += "any(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(any, 0, {
return args[0].base;
})
IMPLEMENT_INTRINSIC_SPIRV(any, 1, {
return
add_instruction(spv::OpAny, convert_type(res_type))
.add(args[0].base);
})
// ret asin(x)
DEFINE_INTRINSIC(asin, 0, float, float)
DEFINE_INTRINSIC(asin, 0, float2, float2)
DEFINE_INTRINSIC(asin, 0, float3, float3)
DEFINE_INTRINSIC(asin, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(asin, 0, {
code += "asin(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(asin, 0, {
code += "asin(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(asin, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Asin)
.add(args[0].base);
})
// ret acos(x)
DEFINE_INTRINSIC(acos, 0, float, float)
DEFINE_INTRINSIC(acos, 0, float2, float2)
DEFINE_INTRINSIC(acos, 0, float3, float3)
DEFINE_INTRINSIC(acos, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(acos, 0, {
code += "acos(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(acos, 0, {
code += "acos(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(acos, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Acos)
.add(args[0].base);
})
// ret atan(x)
DEFINE_INTRINSIC(atan, 0, float, float)
DEFINE_INTRINSIC(atan, 0, float2, float2)
DEFINE_INTRINSIC(atan, 0, float3, float3)
DEFINE_INTRINSIC(atan, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(atan, 0, {
code += "atan(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atan, 0, {
code += "atan(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atan, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Atan)
.add(args[0].base);
})
// ret atan2(x, y)
DEFINE_INTRINSIC(atan2, 0, float, float, float)
DEFINE_INTRINSIC(atan2, 0, float2, float2, float2)
DEFINE_INTRINSIC(atan2, 0, float3, float3, float3)
DEFINE_INTRINSIC(atan2, 0, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(atan2, 0, {
code += "atan(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atan2, 0, {
code += "atan2(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atan2, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Atan2)
.add(args[0].base)
.add(args[1].base);
})
// ret sin(x)
DEFINE_INTRINSIC(sin, 0, float, float)
DEFINE_INTRINSIC(sin, 0, float2, float2)
DEFINE_INTRINSIC(sin, 0, float3, float3)
DEFINE_INTRINSIC(sin, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(sin, 0, {
code += "sin(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(sin, 0, {
code += "sin(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(sin, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Sin)
.add(args[0].base);
})
// ret sinh(x)
DEFINE_INTRINSIC(sinh, 0, float, float)
DEFINE_INTRINSIC(sinh, 0, float2, float2)
DEFINE_INTRINSIC(sinh, 0, float3, float3)
DEFINE_INTRINSIC(sinh, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(sinh, 0, {
code += "sinh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(sinh, 0, {
code += "sinh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(sinh, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Sinh)
.add(args[0].base);
})
// ret cos(x)
DEFINE_INTRINSIC(cos, 0, float, float)
DEFINE_INTRINSIC(cos, 0, float2, float2)
DEFINE_INTRINSIC(cos, 0, float3, float3)
DEFINE_INTRINSIC(cos, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(cos, 0, {
code += "cos(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(cos, 0, {
code += "cos(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(cos, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Cos)
.add(args[0].base);
})
// ret cosh(x)
DEFINE_INTRINSIC(cosh, 0, float, float)
DEFINE_INTRINSIC(cosh, 0, float2, float2)
DEFINE_INTRINSIC(cosh, 0, float3, float3)
DEFINE_INTRINSIC(cosh, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(cosh, 0, {
code += "cosh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(cosh, 0, {
code += "cosh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(cosh, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Cosh)
.add(args[0].base);
})
// ret tan(x)
DEFINE_INTRINSIC(tan, 0, float, float)
DEFINE_INTRINSIC(tan, 0, float2, float2)
DEFINE_INTRINSIC(tan, 0, float3, float3)
DEFINE_INTRINSIC(tan, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(tan, 0, {
code += "tan(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tan, 0, {
code += "tan(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(tan, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Tan)
.add(args[0].base);
})
// ret tanh(x)
DEFINE_INTRINSIC(tanh, 0, float, float)
DEFINE_INTRINSIC(tanh, 0, float2, float2)
DEFINE_INTRINSIC(tanh, 0, float3, float3)
DEFINE_INTRINSIC(tanh, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(tanh, 0, {
code += "tanh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tanh, 0, {
code += "tanh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(tanh, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Tanh)
.add(args[0].base);
})
// sincos(x, out s, out c)
DEFINE_INTRINSIC(sincos, 0, void, float, out_float, out_float)
DEFINE_INTRINSIC(sincos, 0, void, float2, out_float2, out_float2)
DEFINE_INTRINSIC(sincos, 0, void, float3, out_float3, out_float3)
DEFINE_INTRINSIC(sincos, 0, void, float4, out_float4, out_float4)
IMPLEMENT_INTRINSIC_GLSL(sincos, 0, {
code += id_to_name(args[1].base) + " = sin(" + id_to_name(args[0].base) + "), " + id_to_name(args[2].base) + " = cos(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(sincos, 0, {
code += "sincos(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(sincos, 0, {
const spv::Id sin_result = add_instruction(spv::OpExtInst, convert_type(args[0].type))
.add(_glsl_ext)
.add(spv::GLSLstd450Sin)
.add(args[0].base);
const spv::Id cos_result = add_instruction(spv::OpExtInst, convert_type(args[0].type))
.add(_glsl_ext)
.add(spv::GLSLstd450Cos)
.add(args[0].base);
add_instruction_without_result(spv::OpStore)
.add(args[1].base)
.add(sin_result);
add_instruction_without_result(spv::OpStore)
.add(args[2].base)
.add(cos_result);
return 0;
})
// ret asint(x)
DEFINE_INTRINSIC(asint, 0, int, float)
DEFINE_INTRINSIC(asint, 0, int2, float2)
DEFINE_INTRINSIC(asint, 0, int3, float3)
DEFINE_INTRINSIC(asint, 0, int4, float4)
IMPLEMENT_INTRINSIC_GLSL(asint, 0, {
code += "floatBitsToInt(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(asint, 0, {
_uses_bitwise_cast = true;
if (_shader_model < 40)
code += "__";
code += "asint(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(asint, 0, {
return
add_instruction(spv::OpBitcast, convert_type(res_type))
.add(args[0].base);
})
// ret asuint(x)
DEFINE_INTRINSIC(asuint, 0, uint, float)
DEFINE_INTRINSIC(asuint, 0, uint2, float2)
DEFINE_INTRINSIC(asuint, 0, uint3, float3)
DEFINE_INTRINSIC(asuint, 0, uint4, float4)
IMPLEMENT_INTRINSIC_GLSL(asuint, 0, {
code += "floatBitsToUint(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(asuint, 0, {
_uses_bitwise_cast = true;
if (_shader_model < 40)
code += "__";
code += "asuint(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(asuint, 0, {
return
add_instruction(spv::OpBitcast, convert_type(res_type))
.add(args[0].base);
})
// ret asfloat(x)
DEFINE_INTRINSIC(asfloat, 0, float, int)
DEFINE_INTRINSIC(asfloat, 0, float2, int2)
DEFINE_INTRINSIC(asfloat, 0, float3, int3)
DEFINE_INTRINSIC(asfloat, 0, float4, int4)
DEFINE_INTRINSIC(asfloat, 1, float, uint)
DEFINE_INTRINSIC(asfloat, 1, float2, uint2)
DEFINE_INTRINSIC(asfloat, 1, float3, uint3)
DEFINE_INTRINSIC(asfloat, 1, float4, uint4)
IMPLEMENT_INTRINSIC_GLSL(asfloat, 0, {
code += "intBitsToFloat(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(asfloat, 1, {
code += "uintBitsToFloat(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(asfloat, 0, {
_uses_bitwise_cast = true;
if (_shader_model < 40)
code += "__";
code += "asfloat(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(asfloat, 1, {
_uses_bitwise_cast = true;
if (_shader_model < 40)
code += "__";
code += "asfloat(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(asfloat, 0, {
return
add_instruction(spv::OpBitcast, convert_type(res_type))
.add(args[0].base);
})
IMPLEMENT_INTRINSIC_SPIRV(asfloat, 1, {
return
add_instruction(spv::OpBitcast, convert_type(res_type))
.add(args[0].base);
})
// ret f16tof32(x)
DEFINE_INTRINSIC(f16tof32, 0, float, uint)
DEFINE_INTRINSIC(f16tof32, 0, float2, uint2)
DEFINE_INTRINSIC(f16tof32, 0, float3, uint3)
DEFINE_INTRINSIC(f16tof32, 0, float4, uint4)
IMPLEMENT_INTRINSIC_GLSL(f16tof32, 0, {
if (args[0].type.rows > 1)
code += "vec" + std::to_string(args[0].type.rows) + '(';
for (unsigned int i = 0; i < args[0].type.rows; ++i)
{
assert(i < 4);
code += "unpackHalf2x16(" + id_to_name(args[0].base) + '.' + "xyzw"[i] + ").x";
if (i < args[0].type.rows - 1)
code += ", ";
}
if (args[0].type.rows > 1)
code += ')';
})
IMPLEMENT_INTRINSIC_HLSL(f16tof32, 0, {
code += "f16tof32(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(f16tof32, 0, {
type res_scalar_type = res_type;
res_scalar_type.rows = 1;
type res_vector_type = res_type;
res_vector_type.rows = 2;
type arg_scalar_type = args[0].type;
arg_scalar_type.rows = 1;
spv::Id res[4] = {};
for (unsigned int i = 0; i < args[0].type.rows; ++i)
{
assert(i < 4);
spv::Id arg_scalar = args[0].base;
if (args[0].type.rows > 1)
arg_scalar = add_instruction(spv::OpCompositeExtract, convert_type(arg_scalar_type))
.add(arg_scalar)
.add(i);
spv::Id arg_vector = add_instruction(spv::OpExtInst, convert_type(res_vector_type))
.add(_glsl_ext)
.add(spv::GLSLstd450UnpackHalf2x16)
.add(arg_scalar);
res[i] = add_instruction(spv::OpCompositeExtract, convert_type(res_scalar_type))
.add(arg_vector)
.add(0u);
}
if (res_type.rows > 1)
return
add_instruction(spv::OpCompositeConstruct, convert_type(res_type))
.add(res, res + res_type.rows);
else
return res[0];
})
// ret f32tof16(x)
DEFINE_INTRINSIC(f32tof16, 0, uint, float)
DEFINE_INTRINSIC(f32tof16, 0, uint2, float2)
DEFINE_INTRINSIC(f32tof16, 0, uint3, float3)
DEFINE_INTRINSIC(f32tof16, 0, uint4, float4)
IMPLEMENT_INTRINSIC_GLSL(f32tof16, 0, {
if (args[0].type.rows > 1)
code += "uvec" + std::to_string(args[0].type.rows) + '(';
for (unsigned int i = 0; i < args[0].type.rows; ++i)
{
assert(i < 4);
code += "packHalf2x16(vec2(" + id_to_name(args[0].base) + '.' + "xyzw"[i] + ", 0.0))";
if (i < args[0].type.rows - 1)
code += ", ";
}
if (args[0].type.rows > 1)
code += ')';
})
IMPLEMENT_INTRINSIC_HLSL(f32tof16, 0, {
code += "f32tof16(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(f32tof16, 0, {
type res_scalar_type = res_type;
res_scalar_type.rows = 1;
type arg_scalar_type = args[0].type;
arg_scalar_type.rows = 1;
type arg_vector_type = args[0].type;
arg_vector_type.rows = 2;
const spv::Id constant_zero = emit_constant(arg_scalar_type, 0u);
spv::Id res[4] = {};
for (unsigned int i = 0; i < args[0].type.rows; ++i)
{
assert(i < 4);
spv::Id arg_scalar = args[0].base;
if (args[0].type.rows > 1)
arg_scalar = add_instruction(spv::OpCompositeExtract, convert_type(arg_scalar_type))
.add(arg_scalar)
.add(i);
spv::Id arg_vector = add_instruction(spv::OpCompositeConstruct, convert_type(arg_vector_type))
.add(arg_scalar)
.add(constant_zero);
res[i] = add_instruction(spv::OpExtInst, convert_type(res_scalar_type))
.add(_glsl_ext)
.add(spv::GLSLstd450PackHalf2x16)
.add(arg_vector);
}
if (res_type.rows > 1)
return
add_instruction(spv::OpCompositeConstruct, convert_type(res_type))
.add(res, res + res_type.rows);
else
return res[0];
})
// ret firstbitlow
DEFINE_INTRINSIC(firstbitlow, 0, uint, uint)
DEFINE_INTRINSIC(firstbitlow, 0, uint2, uint2)
DEFINE_INTRINSIC(firstbitlow, 0, uint3, uint3)
DEFINE_INTRINSIC(firstbitlow, 0, uint4, uint4)
IMPLEMENT_INTRINSIC_GLSL(firstbitlow, 0, {
code += "findLSB(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(firstbitlow, 0, {
_uses_bitwise_intrinsics = true;
if (_shader_model < 50)
code += "__";
code += "firstbitlow(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(firstbitlow, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FindILsb)
.add(args[0].base);
})
// ret firstbithigh
DEFINE_INTRINSIC(firstbithigh, 0, int, int)
DEFINE_INTRINSIC(firstbithigh, 0, int2, int2)
DEFINE_INTRINSIC(firstbithigh, 0, int3, int3)
DEFINE_INTRINSIC(firstbithigh, 0, int4, int4)
DEFINE_INTRINSIC(firstbithigh, 1, uint, uint)
DEFINE_INTRINSIC(firstbithigh, 1, uint2, uint2)
DEFINE_INTRINSIC(firstbithigh, 1, uint3, uint3)
DEFINE_INTRINSIC(firstbithigh, 1, uint4, uint4)
IMPLEMENT_INTRINSIC_GLSL(firstbithigh, 0, {
code += "findMSB(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(firstbithigh, 1, {
code += "findMSB(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(firstbithigh, 0, {
_uses_bitwise_intrinsics = true;
if (_shader_model < 50)
code += "__";
code += "firstbithigh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(firstbithigh, 1, {
_uses_bitwise_intrinsics = true;
if (_shader_model < 50)
code += "__";
code += "firstbithigh(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(firstbithigh, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FindSMsb)
.add(args[0].base);
})
IMPLEMENT_INTRINSIC_SPIRV(firstbithigh, 1, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FindUMsb)
.add(args[0].base);
})
// ret countbits
DEFINE_INTRINSIC(countbits, 0, uint, uint)
DEFINE_INTRINSIC(countbits, 0, uint2, uint2)
DEFINE_INTRINSIC(countbits, 0, uint3, uint3)
DEFINE_INTRINSIC(countbits, 0, uint4, uint4)
IMPLEMENT_INTRINSIC_GLSL(countbits, 0, {
code += "bitCount(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(countbits, 0, {
_uses_bitwise_intrinsics = true;
if (_shader_model < 50)
code += "__";
code += "countbits(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(countbits, 0, {
return
add_instruction(spv::OpBitCount, convert_type(res_type))
.add(args[0].base);
})
// ret reversebits
DEFINE_INTRINSIC(reversebits, 0, uint, uint)
DEFINE_INTRINSIC(reversebits, 0, uint2, uint2)
DEFINE_INTRINSIC(reversebits, 0, uint3, uint3)
DEFINE_INTRINSIC(reversebits, 0, uint4, uint4)
IMPLEMENT_INTRINSIC_GLSL(reversebits, 0, {
code += "bitfieldReverse(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(reversebits, 0, {
_uses_bitwise_intrinsics = true;
if (_shader_model < 50)
code += "__";
code += "reversebits(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(reversebits, 0, {
return
add_instruction(spv::OpBitReverse, convert_type(res_type))
.add(args[0].base);
})
// ret ceil(x)
DEFINE_INTRINSIC(ceil, 0, float, float)
DEFINE_INTRINSIC(ceil, 0, float2, float2)
DEFINE_INTRINSIC(ceil, 0, float3, float3)
DEFINE_INTRINSIC(ceil, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ceil, 0, {
code += "ceil(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ceil, 0, {
code += "ceil(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ceil, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Ceil)
.add(args[0].base);
})
// ret floor(x)
DEFINE_INTRINSIC(floor, 0, float, float)
DEFINE_INTRINSIC(floor, 0, float2, float2)
DEFINE_INTRINSIC(floor, 0, float3, float3)
DEFINE_INTRINSIC(floor, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(floor, 0, {
code += "floor(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(floor, 0, {
if (_shader_model >= 40)
code += "floor(" + id_to_name(args[0].base) + ')';
else // Using the floor intrinsic sometimes causes the SM3 D3DCompiler to generate wrong code, so replace it with a custom implementation
code += id_to_name(args[0].base) + " - frac(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(floor, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Floor)
.add(args[0].base);
})
// ret clamp(x, min, max)
DEFINE_INTRINSIC(clamp, 0, int, int, int, int)
DEFINE_INTRINSIC(clamp, 0, int2, int2, int2, int2)
DEFINE_INTRINSIC(clamp, 0, int3, int3, int3, int3)
DEFINE_INTRINSIC(clamp, 0, int4, int4, int4, int4)
DEFINE_INTRINSIC(clamp, 1, uint, uint, uint, uint)
DEFINE_INTRINSIC(clamp, 1, uint2, uint2, uint2, uint2)
DEFINE_INTRINSIC(clamp, 1, uint3, uint3, uint3, uint3)
DEFINE_INTRINSIC(clamp, 1, uint4, uint4, uint4, uint4)
DEFINE_INTRINSIC(clamp, 2, float, float, float, float)
DEFINE_INTRINSIC(clamp, 2, float2, float2, float2, float2)
DEFINE_INTRINSIC(clamp, 2, float3, float3, float3, float3)
DEFINE_INTRINSIC(clamp, 2, float4, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(clamp, 0, {
code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(clamp, 1, {
code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(clamp, 2, {
code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(clamp, 0, {
code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(clamp, 1, {
code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(clamp, 2, {
code += "clamp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(clamp, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450SClamp)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(clamp, 1, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450UClamp)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(clamp, 2, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FClamp)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
// ret saturate(x)
DEFINE_INTRINSIC(saturate, 0, float, float)
DEFINE_INTRINSIC(saturate, 0, float2, float2)
DEFINE_INTRINSIC(saturate, 0, float3, float3)
DEFINE_INTRINSIC(saturate, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(saturate, 0, {
code += "clamp(" + id_to_name(args[0].base) + ", 0.0, 1.0)";
})
IMPLEMENT_INTRINSIC_HLSL(saturate, 0, {
code += "saturate(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(saturate, 0, {
const spv::Id constant_one = emit_constant(args[0].type, 1u);
const spv::Id constant_zero = emit_constant(args[0].type, 0u);
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FClamp)
.add(args[0].base)
.add(constant_zero)
.add(constant_one);
})
// ret mad(mvalue, avalue, bvalue)
DEFINE_INTRINSIC(mad, 0, float, float, float, float)
DEFINE_INTRINSIC(mad, 0, float2, float2, float2, float2)
DEFINE_INTRINSIC(mad, 0, float3, float3, float3, float3)
DEFINE_INTRINSIC(mad, 0, float4, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(mad, 0, {
code += "fma(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mad, 0, {
if (_shader_model >= 50)
code += "mad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else
code += id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(mad, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Fma)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
// ret rcp(x)
DEFINE_INTRINSIC(rcp, 0, float, float)
DEFINE_INTRINSIC(rcp, 0, float2, float2)
DEFINE_INTRINSIC(rcp, 0, float3, float3)
DEFINE_INTRINSIC(rcp, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(rcp, 0, {
code += "1.0 / " + id_to_name(args[0].base);
})
IMPLEMENT_INTRINSIC_HLSL(rcp, 0, {
if (_shader_model >= 50)
code += "rcp(" + id_to_name(args[0].base) + ')';
else
code += "1.0 / " + id_to_name(args[0].base);
})
IMPLEMENT_INTRINSIC_SPIRV(rcp, 0, {
const spv::Id constant_one = emit_constant(args[0].type, 1u);
return
add_instruction(spv::OpFDiv, convert_type(res_type))
.add(constant_one)
.add(args[0].base);
})
// ret pow(x, y)
DEFINE_INTRINSIC(pow, 0, float, float, float)
DEFINE_INTRINSIC(pow, 0, float2, float2, float2)
DEFINE_INTRINSIC(pow, 0, float3, float3, float3)
DEFINE_INTRINSIC(pow, 0, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(pow, 0, {
code += "pow(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(pow, 0, {
code += "pow(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(pow, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Pow)
.add(args[0].base)
.add(args[1].base);
})
// ret exp(x)
DEFINE_INTRINSIC(exp, 0, float, float)
DEFINE_INTRINSIC(exp, 0, float2, float2)
DEFINE_INTRINSIC(exp, 0, float3, float3)
DEFINE_INTRINSIC(exp, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(exp, 0, {
code += "exp(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(exp, 0, {
code += "exp(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(exp, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Exp)
.add(args[0].base);
})
// ret exp2(x)
DEFINE_INTRINSIC(exp2, 0, float, float)
DEFINE_INTRINSIC(exp2, 0, float2, float2)
DEFINE_INTRINSIC(exp2, 0, float3, float3)
DEFINE_INTRINSIC(exp2, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(exp2, 0, {
code += "exp2(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(exp2, 0, {
code += "exp2(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(exp2, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Exp2)
.add(args[0].base);
})
// ret log(x)
DEFINE_INTRINSIC(log, 0, float, float)
DEFINE_INTRINSIC(log, 0, float2, float2)
DEFINE_INTRINSIC(log, 0, float3, float3)
DEFINE_INTRINSIC(log, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(log, 0, {
code += "log(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(log, 0, {
code += "log(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(log, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Log)
.add(args[0].base);
})
// ret log2(x)
DEFINE_INTRINSIC(log2, 0, float, float)
DEFINE_INTRINSIC(log2, 0, float2, float2)
DEFINE_INTRINSIC(log2, 0, float3, float3)
DEFINE_INTRINSIC(log2, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(log2, 0, {
code += "log2(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(log2, 0, {
code += "log2(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(log2, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Log2)
.add(args[0].base);
})
// ret log10(x)
DEFINE_INTRINSIC(log10, 0, float, float)
DEFINE_INTRINSIC(log10, 0, float2, float2)
DEFINE_INTRINSIC(log10, 0, float3, float3)
DEFINE_INTRINSIC(log10, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(log10, 0, {
code += "(log2(" + id_to_name(args[0].base) + ") / log2(10.0))";
})
IMPLEMENT_INTRINSIC_HLSL(log10, 0, {
code += "(log2(" + id_to_name(args[0].base) + ") / log2(10.0))";
})
IMPLEMENT_INTRINSIC_SPIRV(log10, 0, {
const spv::Id log2 = add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Log2)
.add(args[0].base);
const spv::Id log10 = emit_constant(args[0].type, /* log2(10) */
constant { { 3.321928f, 3.321928f, 3.321928f, 3.321928f } });
return
add_instruction(spv::OpFDiv, convert_type(res_type))
.add(log2)
.add(log10); })
// ret sign(x)
DEFINE_INTRINSIC(sign, 0, int, int)
DEFINE_INTRINSIC(sign, 0, int2, int2)
DEFINE_INTRINSIC(sign, 0, int3, int3)
DEFINE_INTRINSIC(sign, 0, int4, int4)
DEFINE_INTRINSIC(sign, 1, float, float)
DEFINE_INTRINSIC(sign, 1, float2, float2)
DEFINE_INTRINSIC(sign, 1, float3, float3)
DEFINE_INTRINSIC(sign, 1, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(sign, 0, {
code += "sign(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(sign, 1, {
code += "sign(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(sign, 0, {
code += "sign(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(sign, 1, {
code += "sign(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(sign, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450SSign)
.add(args[0].base);
})
IMPLEMENT_INTRINSIC_SPIRV(sign, 1, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FSign)
.add(args[0].base);
})
// ret sqrt(x)
DEFINE_INTRINSIC(sqrt, 0, float, float)
DEFINE_INTRINSIC(sqrt, 0, float2, float2)
DEFINE_INTRINSIC(sqrt, 0, float3, float3)
DEFINE_INTRINSIC(sqrt, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(sqrt, 0, {
code += "sqrt(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(sqrt, 0, {
code += "sqrt(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(sqrt, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Sqrt)
.add(args[0].base);
})
// ret rsqrt(x)
DEFINE_INTRINSIC(rsqrt, 0, float, float)
DEFINE_INTRINSIC(rsqrt, 0, float2, float2)
DEFINE_INTRINSIC(rsqrt, 0, float3, float3)
DEFINE_INTRINSIC(rsqrt, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(rsqrt, 0, {
code += "inversesqrt(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(rsqrt, 0, {
code += "rsqrt(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(rsqrt, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450InverseSqrt)
.add(args[0].base);
})
// ret lerp(x, y, s)
DEFINE_INTRINSIC(lerp, 0, float, float, float, float)
DEFINE_INTRINSIC(lerp, 0, float2, float2, float2, float2)
DEFINE_INTRINSIC(lerp, 0, float3, float3, float3, float3)
DEFINE_INTRINSIC(lerp, 0, float4, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(lerp, 0, {
code += "mix(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(lerp, 0, {
code += "lerp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(lerp, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FMix)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
// ret step(y, x)
DEFINE_INTRINSIC(step, 0, float, float, float)
DEFINE_INTRINSIC(step, 0, float2, float2, float2)
DEFINE_INTRINSIC(step, 0, float3, float3, float3)
DEFINE_INTRINSIC(step, 0, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(step, 0, {
code += "step(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(step, 0, {
code += "step(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(step, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Step)
.add(args[0].base)
.add(args[1].base);
})
// ret smoothstep(min, max, x)
DEFINE_INTRINSIC(smoothstep, 0, float, float, float, float)
DEFINE_INTRINSIC(smoothstep, 0, float2, float2, float2, float2)
DEFINE_INTRINSIC(smoothstep, 0, float3, float3, float3, float3)
DEFINE_INTRINSIC(smoothstep, 0, float4, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(smoothstep, 0, {
code += "smoothstep(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(smoothstep, 0, {
code += "smoothstep(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(smoothstep, 0, {
return
add_instruction(spv::OpExtInst, convert_type(args[2].type))
.add(_glsl_ext)
.add(spv::GLSLstd450SmoothStep)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
// ret frac(x)
DEFINE_INTRINSIC(frac, 0, float, float)
DEFINE_INTRINSIC(frac, 0, float2, float2)
DEFINE_INTRINSIC(frac, 0, float3, float3)
DEFINE_INTRINSIC(frac, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(frac, 0, {
code += "fract(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(frac, 0, {
code += "frac(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(frac, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Fract)
.add(args[0].base);
})
// ret ldexp(x, exp)
DEFINE_INTRINSIC(ldexp, 0, float, float, int)
DEFINE_INTRINSIC(ldexp, 0, float2, float2, int2)
DEFINE_INTRINSIC(ldexp, 0, float3, float3, int3)
DEFINE_INTRINSIC(ldexp, 0, float4, float4, int4)
IMPLEMENT_INTRINSIC_GLSL(ldexp, 0, {
code += "ldexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ldexp, 0, {
code += "ldexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ldexp, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Ldexp)
.add(args[0].base)
.add(args[1].base);
})
// ret modf(x, out ip)
DEFINE_INTRINSIC(modf, 0, float, float, out_float)
DEFINE_INTRINSIC(modf, 0, float2, float2, out_float2)
DEFINE_INTRINSIC(modf, 0, float3, float3, out_float3)
DEFINE_INTRINSIC(modf, 0, float4, float4, out_float4)
IMPLEMENT_INTRINSIC_GLSL(modf, 0, {
code += "modf(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(modf, 0, {
code += "modf(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(modf, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Modf)
.add(args[0].base)
.add(args[1].base);
})
// ret frexp(x, out exp)
DEFINE_INTRINSIC(frexp, 0, float, float, out_int)
DEFINE_INTRINSIC(frexp, 0, float2, float2, out_int2)
DEFINE_INTRINSIC(frexp, 0, float3, float3, out_int3)
DEFINE_INTRINSIC(frexp, 0, float4, float4, out_int4)
IMPLEMENT_INTRINSIC_GLSL(frexp, 0, {
code += "frexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(frexp, 0, {
code += "frexp(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(frexp, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Frexp)
.add(args[0].base)
.add(args[1].base);
})
// ret trunc(x)
DEFINE_INTRINSIC(trunc, 0, float, float)
DEFINE_INTRINSIC(trunc, 0, float2, float2)
DEFINE_INTRINSIC(trunc, 0, float3, float3)
DEFINE_INTRINSIC(trunc, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(trunc, 0, {
code += "trunc(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(trunc, 0, {
code += "trunc(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(trunc, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Trunc)
.add(args[0].base);
})
// ret round(x)
DEFINE_INTRINSIC(round, 0, float, float)
DEFINE_INTRINSIC(round, 0, float2, float2)
DEFINE_INTRINSIC(round, 0, float3, float3)
DEFINE_INTRINSIC(round, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(round, 0, {
code += "round(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(round, 0, {
code += "round(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(round, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Round)
.add(args[0].base);
})
// ret min(x, y)
DEFINE_INTRINSIC(min, 0, int, int, int)
DEFINE_INTRINSIC(min, 0, int2, int2, int2)
DEFINE_INTRINSIC(min, 0, int3, int3, int3)
DEFINE_INTRINSIC(min, 0, int4, int4, int4)
DEFINE_INTRINSIC(min, 1, float, float, float)
DEFINE_INTRINSIC(min, 1, float2, float2, float2)
DEFINE_INTRINSIC(min, 1, float3, float3, float3)
DEFINE_INTRINSIC(min, 1, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(min, 0, {
code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(min, 1, {
code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(min, 0, {
code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(min, 1, {
code += "min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(min, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450SMin)
.add(args[0].base)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(min, 1, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FMin)
.add(args[0].base)
.add(args[1].base);
})
// ret max(x, y)
DEFINE_INTRINSIC(max, 0, int, int, int)
DEFINE_INTRINSIC(max, 0, int2, int2, int2)
DEFINE_INTRINSIC(max, 0, int3, int3, int3)
DEFINE_INTRINSIC(max, 0, int4, int4, int4)
DEFINE_INTRINSIC(max, 1, float, float, float)
DEFINE_INTRINSIC(max, 1, float2, float2, float2)
DEFINE_INTRINSIC(max, 1, float3, float3, float3)
DEFINE_INTRINSIC(max, 1, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(max, 0, {
code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(max, 1, {
code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(max, 0, {
code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(max, 1, {
code += "max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(max, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450SMax)
.add(args[0].base)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(max, 1, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FMax)
.add(args[0].base)
.add(args[1].base);
})
// ret degrees(x)
DEFINE_INTRINSIC(degrees, 0, float, float)
DEFINE_INTRINSIC(degrees, 0, float2, float2)
DEFINE_INTRINSIC(degrees, 0, float3, float3)
DEFINE_INTRINSIC(degrees, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(degrees, 0, {
code += "degrees(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(degrees, 0, {
code += "degrees(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(degrees, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Degrees)
.add(args[0].base);
})
// ret radians(x)
DEFINE_INTRINSIC(radians, 0, float, float)
DEFINE_INTRINSIC(radians, 0, float2, float2)
DEFINE_INTRINSIC(radians, 0, float3, float3)
DEFINE_INTRINSIC(radians, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(radians, 0, {
code += "radians(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(radians, 0, {
code += "radians(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(radians, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Radians)
.add(args[0].base);
})
// ret ddx(x)
DEFINE_INTRINSIC(ddx, 0, float, float)
DEFINE_INTRINSIC(ddx, 0, float2, float2)
DEFINE_INTRINSIC(ddx, 0, float3, float3)
DEFINE_INTRINSIC(ddx, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ddx, 0, {
code += "dFdx(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ddx, 0, {
code += "ddx(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ddx, 0, {
return
add_instruction(spv::OpDPdx, convert_type(res_type))
.add(args[0].base);
})
// ret ddx_coarse(x)
DEFINE_INTRINSIC(ddx_coarse, 0, float, float)
DEFINE_INTRINSIC(ddx_coarse, 0, float2, float2)
DEFINE_INTRINSIC(ddx_coarse, 0, float3, float3)
DEFINE_INTRINSIC(ddx_coarse, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ddx_coarse, 0, {
code += "dFdxCoarse(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ddx_coarse, 0, {
code += (_shader_model >= 50 ? "ddx_coarse(" : "ddx(") + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ddx_coarse, 0, {
return
add_instruction(spv::OpDPdxCoarse, convert_type(res_type))
.add(args[0].base);
})
// ret ddx_fine(x)
DEFINE_INTRINSIC(ddx_fine, 0, float, float)
DEFINE_INTRINSIC(ddx_fine, 0, float2, float2)
DEFINE_INTRINSIC(ddx_fine, 0, float3, float3)
DEFINE_INTRINSIC(ddx_fine, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ddx_fine, 0, {
code += "dFdxFine(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ddx_fine, 0, {
code += (_shader_model >= 50 ? "ddx_fine(" : "ddx(") + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ddx_fine, 0, {
return
add_instruction(spv::OpDPdxFine, convert_type(res_type))
.add(args[0].base);
})
// ret ddy(x)
DEFINE_INTRINSIC(ddy, 0, float, float)
DEFINE_INTRINSIC(ddy, 0, float2, float2)
DEFINE_INTRINSIC(ddy, 0, float3, float3)
DEFINE_INTRINSIC(ddy, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ddy, 0, {
code += "dFdy(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ddy, 0, {
code += "ddy(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ddy, 0, {
return
add_instruction(spv::OpDPdy, convert_type(res_type))
.add(args[0].base);
})
// ret ddy_coarse(x)
DEFINE_INTRINSIC(ddy_coarse, 0, float, float)
DEFINE_INTRINSIC(ddy_coarse, 0, float2, float2)
DEFINE_INTRINSIC(ddy_coarse, 0, float3, float3)
DEFINE_INTRINSIC(ddy_coarse, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ddy_coarse, 0, {
code += "dFdyCoarse(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ddy_coarse, 0, {
code += (_shader_model >= 50 ? "ddy_coarse(" : "ddy(") + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ddy_coarse, 0, {
return
add_instruction(spv::OpDPdyCoarse, convert_type(res_type))
.add(args[0].base);
})
// ret ddy_fine(x)
DEFINE_INTRINSIC(ddy_fine, 0, float, float)
DEFINE_INTRINSIC(ddy_fine, 0, float2, float2)
DEFINE_INTRINSIC(ddy_fine, 0, float3, float3)
DEFINE_INTRINSIC(ddy_fine, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(ddy_fine, 0, {
code += "dFdyFine(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(ddy_fine, 0, {
code += (_shader_model >= 50 ? "ddy_fine(" : "ddy(") + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(ddy_fine, 0, {
return
add_instruction(spv::OpDPdyFine, convert_type(res_type))
.add(args[0].base);
})
// ret fwidth(x)
DEFINE_INTRINSIC(fwidth, 0, float, float)
DEFINE_INTRINSIC(fwidth, 0, float2, float2)
DEFINE_INTRINSIC(fwidth, 0, float3, float3)
DEFINE_INTRINSIC(fwidth, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(fwidth, 0, {
code += "fwidth(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(fwidth, 0, {
code += "fwidth(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(fwidth, 0, {
return
add_instruction(spv::OpFwidth, convert_type(res_type))
.add(args[0].base);
})
// ret dot(x, y)
DEFINE_INTRINSIC(dot, 0, float, float, float)
DEFINE_INTRINSIC(dot, 1, float, float2, float2)
DEFINE_INTRINSIC(dot, 1, float, float3, float3)
DEFINE_INTRINSIC(dot, 1, float, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(dot, 0, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(dot, 1, {
code += "dot(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(dot, 0, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(dot, 1, {
code += "dot(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(dot, 0, {
return
add_instruction(spv::OpFMul, convert_type(res_type))
.add(args[0].base)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(dot, 1, {
return
add_instruction(spv::OpDot, convert_type(res_type))
.add(args[0].base)
.add(args[1].base);
})
// ret cross(x, y)
DEFINE_INTRINSIC(cross, 0, float3, float3, float3)
IMPLEMENT_INTRINSIC_GLSL(cross, 0, {
code += "cross(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(cross, 0, {
code += "cross(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(cross, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Cross)
.add(args[0].base)
.add(args[1].base);
})
// ret length(x)
DEFINE_INTRINSIC(length, 0, float, float)
DEFINE_INTRINSIC(length, 0, float, float2)
DEFINE_INTRINSIC(length, 0, float, float3)
DEFINE_INTRINSIC(length, 0, float, float4)
IMPLEMENT_INTRINSIC_GLSL(length, 0, {
code += "length(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(length, 0, {
code += "length(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(length, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Length)
.add(args[0].base);
})
// ret distance(x, y)
DEFINE_INTRINSIC(distance, 0, float, float, float)
DEFINE_INTRINSIC(distance, 0, float, float2, float2)
DEFINE_INTRINSIC(distance, 0, float, float3, float3)
DEFINE_INTRINSIC(distance, 0, float, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(distance, 0, {
code += "distance(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(distance, 0, {
code += "distance(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(distance, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Distance)
.add(args[0].base)
.add(args[1].base);
})
// ret normalize(x)
DEFINE_INTRINSIC(normalize, 0, float2, float2)
DEFINE_INTRINSIC(normalize, 0, float3, float3)
DEFINE_INTRINSIC(normalize, 0, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(normalize, 0, {
code += "normalize(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(normalize, 0, {
code += "normalize(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(normalize, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Normalize)
.add(args[0].base);
})
// ret transpose(x)
DEFINE_INTRINSIC(transpose, 0, float2x2, float2x2)
DEFINE_INTRINSIC(transpose, 0, float2x3, float3x2)
DEFINE_INTRINSIC(transpose, 0, float2x4, float4x2)
DEFINE_INTRINSIC(transpose, 0, float3x2, float2x3)
DEFINE_INTRINSIC(transpose, 0, float3x3, float3x3)
DEFINE_INTRINSIC(transpose, 0, float3x4, float4x3)
DEFINE_INTRINSIC(transpose, 0, float4x2, float2x4)
DEFINE_INTRINSIC(transpose, 0, float4x3, float3x4)
DEFINE_INTRINSIC(transpose, 0, float4x4, float4x4)
IMPLEMENT_INTRINSIC_GLSL(transpose, 0, {
code += "transpose(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(transpose, 0, {
code += "transpose(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(transpose, 0, {
return
add_instruction(spv::OpTranspose, convert_type(res_type))
.add(args[0].base);
})
// ret determinant(m)
DEFINE_INTRINSIC(determinant, 0, float, float2x2)
DEFINE_INTRINSIC(determinant, 0, float, float3x3)
DEFINE_INTRINSIC(determinant, 0, float, float4x4)
IMPLEMENT_INTRINSIC_GLSL(determinant, 0, {
code += "determinant(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(determinant, 0, {
code += "determinant(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(determinant, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Determinant)
.add(args[0].base);
})
// ret reflect(i, n)
DEFINE_INTRINSIC(reflect, 0, float2, float2, float2)
DEFINE_INTRINSIC(reflect, 0, float3, float3, float3)
DEFINE_INTRINSIC(reflect, 0, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(reflect, 0, {
code += "reflect(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(reflect, 0, {
code += "reflect(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(reflect, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Reflect)
.add(args[0].base)
.add(args[1].base);
})
// ret refract(i, n, eta)
DEFINE_INTRINSIC(refract, 0, float2, float2, float2, float)
DEFINE_INTRINSIC(refract, 0, float3, float3, float3, float)
DEFINE_INTRINSIC(refract, 0, float4, float4, float4, float)
IMPLEMENT_INTRINSIC_GLSL(refract, 0, {
code += "refract(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(refract, 0, {
code += "refract(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(refract, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450Refract)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
// ret faceforward(n, i, ng)
DEFINE_INTRINSIC(faceforward, 0, float, float, float, float)
DEFINE_INTRINSIC(faceforward, 0, float2, float2, float2, float2)
DEFINE_INTRINSIC(faceforward, 0, float3, float3, float3, float3)
DEFINE_INTRINSIC(faceforward, 0, float4, float4, float4, float4)
IMPLEMENT_INTRINSIC_GLSL(faceforward, 0, {
code += "faceforward(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(faceforward, 0, {
code += "faceforward(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(faceforward, 0, {
return
add_instruction(spv::OpExtInst, convert_type(res_type))
.add(_glsl_ext)
.add(spv::GLSLstd450FaceForward)
.add(args[0].base)
.add(args[1].base)
.add(args[2].base);
})
// ret mul(x, y)
DEFINE_INTRINSIC(mul, 0, int2, int, int2)
DEFINE_INTRINSIC(mul, 0, int3, int, int3)
DEFINE_INTRINSIC(mul, 0, int4, int, int4)
DEFINE_INTRINSIC(mul, 0, float2, float, float2)
DEFINE_INTRINSIC(mul, 0, float3, float, float3)
DEFINE_INTRINSIC(mul, 0, float4, float, float4)
IMPLEMENT_INTRINSIC_GLSL(mul, 0, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 0, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 0, {
return
add_instruction(spv::OpVectorTimesScalar, convert_type(res_type))
.add(args[1].base)
.add(args[0].base);
})
DEFINE_INTRINSIC(mul, 1, int2, int2, int)
DEFINE_INTRINSIC(mul, 1, int3, int3, int)
DEFINE_INTRINSIC(mul, 1, int4, int4, int)
DEFINE_INTRINSIC(mul, 1, float2, float2, float)
DEFINE_INTRINSIC(mul, 1, float3, float3, float)
DEFINE_INTRINSIC(mul, 1, float4, float4, float)
IMPLEMENT_INTRINSIC_GLSL(mul, 1, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 1, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 1, {
return
add_instruction(spv::OpVectorTimesScalar, convert_type(res_type))
.add(args[0].base)
.add(args[1].base);
})
DEFINE_INTRINSIC(mul, 2, int2x2, int, int2x2)
DEFINE_INTRINSIC(mul, 2, int2x3, int, int2x3)
DEFINE_INTRINSIC(mul, 2, int2x4, int, int2x4)
DEFINE_INTRINSIC(mul, 2, int3x2, int, int3x2)
DEFINE_INTRINSIC(mul, 2, int3x3, int, int3x3)
DEFINE_INTRINSIC(mul, 2, int3x4, int, int3x4)
DEFINE_INTRINSIC(mul, 2, int4x2, int, int4x2)
DEFINE_INTRINSIC(mul, 2, int4x3, int, int4x3)
DEFINE_INTRINSIC(mul, 2, int4x4, int, int4x4)
DEFINE_INTRINSIC(mul, 2, float2x2, float, float2x2)
DEFINE_INTRINSIC(mul, 2, float2x3, float, float2x3)
DEFINE_INTRINSIC(mul, 2, float2x4, float, float2x4)
DEFINE_INTRINSIC(mul, 2, float3x2, float, float3x2)
DEFINE_INTRINSIC(mul, 2, float3x3, float, float3x3)
DEFINE_INTRINSIC(mul, 2, float3x4, float, float3x4)
DEFINE_INTRINSIC(mul, 2, float4x2, float, float4x2)
DEFINE_INTRINSIC(mul, 2, float4x3, float, float4x3)
DEFINE_INTRINSIC(mul, 2, float4x4, float, float4x4)
IMPLEMENT_INTRINSIC_GLSL(mul, 2, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 2, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 2, {
return
add_instruction(spv::OpMatrixTimesScalar, convert_type(res_type))
.add(args[1].base)
.add(args[0].base);
})
DEFINE_INTRINSIC(mul, 3, int2x2, int2x2, int)
DEFINE_INTRINSIC(mul, 3, int2x3, int2x3, int)
DEFINE_INTRINSIC(mul, 3, int2x4, int2x4, int)
DEFINE_INTRINSIC(mul, 3, int3x2, int3x2, int)
DEFINE_INTRINSIC(mul, 3, int3x3, int3x3, int)
DEFINE_INTRINSIC(mul, 3, int3x4, int3x4, int)
DEFINE_INTRINSIC(mul, 3, int4x2, int4x2, int)
DEFINE_INTRINSIC(mul, 3, int4x3, int4x3, int)
DEFINE_INTRINSIC(mul, 3, int4x4, int4x4, int)
DEFINE_INTRINSIC(mul, 3, float2x2, float2x2, float)
DEFINE_INTRINSIC(mul, 3, float2x3, float2x3, float)
DEFINE_INTRINSIC(mul, 3, float2x4, float2x4, float)
DEFINE_INTRINSIC(mul, 3, float3x2, float3x2, float)
DEFINE_INTRINSIC(mul, 3, float3x3, float3x3, float)
DEFINE_INTRINSIC(mul, 3, float3x4, float3x4, float)
DEFINE_INTRINSIC(mul, 3, float4x2, float4x2, float)
DEFINE_INTRINSIC(mul, 3, float4x3, float4x3, float)
DEFINE_INTRINSIC(mul, 3, float4x4, float4x4, float)
IMPLEMENT_INTRINSIC_GLSL(mul, 3, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 3, {
code += '(' + id_to_name(args[0].base) + " * " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 3, {
return
add_instruction(spv::OpMatrixTimesScalar, convert_type(res_type))
.add(args[0].base)
.add(args[1].base);
})
DEFINE_INTRINSIC(mul, 4, int2, int2, int2x2)
DEFINE_INTRINSIC(mul, 4, int3, int2, int2x3)
DEFINE_INTRINSIC(mul, 4, int4, int2, int2x4)
DEFINE_INTRINSIC(mul, 4, int2, int3, int3x2)
DEFINE_INTRINSIC(mul, 4, int3, int3, int3x3)
DEFINE_INTRINSIC(mul, 4, int4, int3, int3x4)
DEFINE_INTRINSIC(mul, 4, int2, int4, int4x2)
DEFINE_INTRINSIC(mul, 4, int3, int4, int4x3)
DEFINE_INTRINSIC(mul, 4, int4, int4, int4x4)
DEFINE_INTRINSIC(mul, 4, float2, float2, float2x2)
DEFINE_INTRINSIC(mul, 4, float3, float2, float2x3)
DEFINE_INTRINSIC(mul, 4, float4, float2, float2x4)
DEFINE_INTRINSIC(mul, 4, float2, float3, float3x2)
DEFINE_INTRINSIC(mul, 4, float3, float3, float3x3)
DEFINE_INTRINSIC(mul, 4, float4, float3, float3x4)
DEFINE_INTRINSIC(mul, 4, float2, float4, float4x2)
DEFINE_INTRINSIC(mul, 4, float3, float4, float4x3)
DEFINE_INTRINSIC(mul, 4, float4, float4, float4x4)
IMPLEMENT_INTRINSIC_GLSL(mul, 4, {
// Flip inputs because matrices are column-wise
code += '(' + id_to_name(args[1].base) + " * " + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 4, {
code += "mul(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 4, {
return
add_instruction(spv::OpMatrixTimesVector, convert_type(res_type))
.add(args[1].base) // Flip inputs because matrices are column-wise
.add(args[0].base);
})
DEFINE_INTRINSIC(mul, 5, int2, int2x2, int2)
DEFINE_INTRINSIC(mul, 5, int2, int2x3, int3)
DEFINE_INTRINSIC(mul, 5, int2, int2x4, int4)
DEFINE_INTRINSIC(mul, 5, int3, int3x2, int2)
DEFINE_INTRINSIC(mul, 5, int3, int3x3, int3)
DEFINE_INTRINSIC(mul, 5, int3, int3x4, int4)
DEFINE_INTRINSIC(mul, 5, int4, int4x2, int2)
DEFINE_INTRINSIC(mul, 5, int4, int4x3, int3)
DEFINE_INTRINSIC(mul, 5, int4, int4x4, int4)
DEFINE_INTRINSIC(mul, 5, float2, float2x2, float2)
DEFINE_INTRINSIC(mul, 5, float2, float2x3, float3)
DEFINE_INTRINSIC(mul, 5, float2, float2x4, float4)
DEFINE_INTRINSIC(mul, 5, float3, float3x2, float2)
DEFINE_INTRINSIC(mul, 5, float3, float3x3, float3)
DEFINE_INTRINSIC(mul, 5, float3, float3x4, float4)
DEFINE_INTRINSIC(mul, 5, float4, float4x2, float2)
DEFINE_INTRINSIC(mul, 5, float4, float4x3, float3)
DEFINE_INTRINSIC(mul, 5, float4, float4x4, float4)
IMPLEMENT_INTRINSIC_GLSL(mul, 5, {
// Flip inputs because matrices are column-wise
code += '(' + id_to_name(args[1].base) + " * " + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 5, {
code += "mul(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 5, {
return
add_instruction(spv::OpVectorTimesMatrix, convert_type(res_type))
.add(args[1].base) // Flip inputs because matrices are column-wise
.add(args[0].base);
})
DEFINE_INTRINSIC(mul, 6, int2x2, int2x2, int2x2)
DEFINE_INTRINSIC(mul, 6, int2x3, int2x2, int2x3)
DEFINE_INTRINSIC(mul, 6, int2x4, int2x2, int2x4)
DEFINE_INTRINSIC(mul, 6, int2x2, int2x3, int3x2)
DEFINE_INTRINSIC(mul, 6, int2x3, int2x3, int3x3)
DEFINE_INTRINSIC(mul, 6, int2x4, int2x3, int3x4)
DEFINE_INTRINSIC(mul, 6, int2x2, int2x4, int4x2)
DEFINE_INTRINSIC(mul, 6, int2x3, int2x4, int4x3)
DEFINE_INTRINSIC(mul, 6, int2x4, int2x4, int4x4)
DEFINE_INTRINSIC(mul, 6, int3x2, int3x2, int2x2)
DEFINE_INTRINSIC(mul, 6, int3x3, int3x2, int2x3)
DEFINE_INTRINSIC(mul, 6, int3x4, int3x2, int2x4)
DEFINE_INTRINSIC(mul, 6, int3x2, int3x3, int3x2)
DEFINE_INTRINSIC(mul, 6, int3x3, int3x3, int3x3)
DEFINE_INTRINSIC(mul, 6, int3x4, int3x3, int3x4)
DEFINE_INTRINSIC(mul, 6, int3x2, int3x4, int4x2)
DEFINE_INTRINSIC(mul, 6, int3x3, int3x4, int4x3)
DEFINE_INTRINSIC(mul, 6, int3x4, int3x4, int4x4)
DEFINE_INTRINSIC(mul, 6, int4x2, int4x2, int2x2)
DEFINE_INTRINSIC(mul, 6, int4x3, int4x2, int2x3)
DEFINE_INTRINSIC(mul, 6, int4x4, int4x2, int2x4)
DEFINE_INTRINSIC(mul, 6, int4x2, int4x3, int3x2)
DEFINE_INTRINSIC(mul, 6, int4x3, int4x3, int3x3)
DEFINE_INTRINSIC(mul, 6, int4x4, int4x3, int3x4)
DEFINE_INTRINSIC(mul, 6, int4x2, int4x4, int4x2)
DEFINE_INTRINSIC(mul, 6, int4x3, int4x4, int4x3)
DEFINE_INTRINSIC(mul, 6, int4x4, int4x4, int4x4)
DEFINE_INTRINSIC(mul, 6, float2x2, float2x2, float2x2)
DEFINE_INTRINSIC(mul, 6, float2x3, float2x2, float2x3)
DEFINE_INTRINSIC(mul, 6, float2x4, float2x2, float2x4)
DEFINE_INTRINSIC(mul, 6, float2x2, float2x3, float3x2)
DEFINE_INTRINSIC(mul, 6, float2x3, float2x3, float3x3)
DEFINE_INTRINSIC(mul, 6, float2x4, float2x3, float3x4)
DEFINE_INTRINSIC(mul, 6, float2x2, float2x4, float4x2)
DEFINE_INTRINSIC(mul, 6, float2x3, float2x4, float4x3)
DEFINE_INTRINSIC(mul, 6, float2x4, float2x4, float4x4)
DEFINE_INTRINSIC(mul, 6, float3x2, float3x2, float2x2)
DEFINE_INTRINSIC(mul, 6, float3x3, float3x2, float2x3)
DEFINE_INTRINSIC(mul, 6, float3x4, float3x2, float2x4)
DEFINE_INTRINSIC(mul, 6, float3x2, float3x3, float3x2)
DEFINE_INTRINSIC(mul, 6, float3x3, float3x3, float3x3)
DEFINE_INTRINSIC(mul, 6, float3x4, float3x3, float3x4)
DEFINE_INTRINSIC(mul, 6, float3x2, float3x4, float4x2)
DEFINE_INTRINSIC(mul, 6, float3x3, float3x4, float4x3)
DEFINE_INTRINSIC(mul, 6, float3x4, float3x4, float4x4)
DEFINE_INTRINSIC(mul, 6, float4x2, float4x2, float2x2)
DEFINE_INTRINSIC(mul, 6, float4x3, float4x2, float2x3)
DEFINE_INTRINSIC(mul, 6, float4x4, float4x2, float2x4)
DEFINE_INTRINSIC(mul, 6, float4x2, float4x3, float3x2)
DEFINE_INTRINSIC(mul, 6, float4x3, float4x3, float3x3)
DEFINE_INTRINSIC(mul, 6, float4x4, float4x3, float3x4)
DEFINE_INTRINSIC(mul, 6, float4x2, float4x4, float4x2)
DEFINE_INTRINSIC(mul, 6, float4x3, float4x4, float4x3)
DEFINE_INTRINSIC(mul, 6, float4x4, float4x4, float4x4)
IMPLEMENT_INTRINSIC_GLSL(mul, 6, {
// Flip inputs because matrices are column-wise
code += '(' + id_to_name(args[1].base) + " * " + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(mul, 6, {
code += "mul(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(mul, 6, {
return
add_instruction(spv::OpMatrixTimesMatrix, convert_type(res_type))
.add(args[1].base) // Flip inputs because matrices are column-wise
.add(args[0].base);
})
// ret isinf(x)
DEFINE_INTRINSIC(isinf, 0, bool, float)
DEFINE_INTRINSIC(isinf, 0, bool2, float2)
DEFINE_INTRINSIC(isinf, 0, bool3, float3)
DEFINE_INTRINSIC(isinf, 0, bool4, float4)
IMPLEMENT_INTRINSIC_GLSL(isinf, 0, {
code += "isinf(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(isinf, 0, {
code += "isinf(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(isinf, 0, {
return
add_instruction(spv::OpIsInf, convert_type(res_type))
.add(args[0].base);
})
// ret isnan(x)
DEFINE_INTRINSIC(isnan, 0, bool, float)
DEFINE_INTRINSIC(isnan, 0, bool2, float2)
DEFINE_INTRINSIC(isnan, 0, bool3, float3)
DEFINE_INTRINSIC(isnan, 0, bool4, float4)
IMPLEMENT_INTRINSIC_GLSL(isnan, 0, {
code += "isnan(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(isnan, 0, {
code += "isnan(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(isnan, 0, {
return
add_instruction(spv::OpIsNan, convert_type(res_type))
.add(args[0].base);
})
// ret tex1D(s, coords)
// ret tex1D(s, coords, offset)
DEFINE_INTRINSIC(tex1D, 0, int, sampler1d_int, float)
DEFINE_INTRINSIC(tex1D, 0, uint, sampler1d_uint, float)
DEFINE_INTRINSIC(tex1D, 0, float, sampler1d_float, float)
DEFINE_INTRINSIC(tex1D, 0, float4, sampler1d_float4, float)
DEFINE_INTRINSIC(tex1D, 1, int, sampler1d_int, float, int)
DEFINE_INTRINSIC(tex1D, 1, uint, sampler1d_uint, float, int)
DEFINE_INTRINSIC(tex1D, 1, float, sampler1d_float, float, int)
DEFINE_INTRINSIC(tex1D, 1, float4, sampler1d_float4, float, int)
IMPLEMENT_INTRINSIC_GLSL(tex1D, 0, {
code += "texture(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex1D, 1, {
code += "textureOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex1D, 0, {
if (_shader_model >= 40) { // SM4 and higher use a more object-oriented programming model for textures
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
else
// Integer sampling is not supported until SM6.7, so emulate with a texture fetch
code += "0; { "
"float _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + " * _dimensions, 0)); }";
}
else {
code += "tex1D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex1D, 1, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else
code += "0; { "
"float _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + " * _dimensions, 0), " + id_to_name(args[2].base) + "); }";
}
else {
code += "tex1D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize)";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex1D, 0, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsMaskNone);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex1D, 1, {
// Non-constant offset operand needs extended capability
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex2D(s, coords)
// ret tex2D(s, coords, offset)
DEFINE_INTRINSIC(tex2D, 0, int, sampler2d_int, float2)
DEFINE_INTRINSIC(tex2D, 0, uint, sampler2d_uint, float2)
DEFINE_INTRINSIC(tex2D, 0, float, sampler2d_float, float2)
DEFINE_INTRINSIC(tex2D, 0, float4, sampler2d_float4, float2)
DEFINE_INTRINSIC(tex2D, 1, int, sampler2d_int, float2, int2)
DEFINE_INTRINSIC(tex2D, 1, uint, sampler2d_uint, float2, int2)
DEFINE_INTRINSIC(tex2D, 1, float, sampler2d_float, float2, int2)
DEFINE_INTRINSIC(tex2D, 1, float4, sampler2d_float4, float2, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2D, 0, {
code += "texture(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex2D, 1, {
code += "textureOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex2D, 0, {
if (_shader_model >= 40) { // SM4 and higher use a more object-oriented programming model for textures
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
else
// Integer sampling is not supported until SM6.7, so emulate with a texture fetch
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + " * _dimensions, 0)); }";
}
else {
code += "tex2D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex2D, 1, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + " * _dimensions, 0), " + id_to_name(args[2].base) + "); }";
}
else {
code += "tex2D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize)";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex2D, 0, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsMaskNone);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex2D, 1, {
// Non-constant offset operand needs extended capability
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex3D(s, coords)
// ret tex3D(s, coords, offset)
DEFINE_INTRINSIC(tex3D, 0, int, sampler3d_int, float3)
DEFINE_INTRINSIC(tex3D, 0, uint, sampler3d_uint, float3)
DEFINE_INTRINSIC(tex3D, 0, float, sampler3d_float, float3)
DEFINE_INTRINSIC(tex3D, 0, float4, sampler3d_float4, float3)
DEFINE_INTRINSIC(tex3D, 1, int, sampler3d_int, float3, int3)
DEFINE_INTRINSIC(tex3D, 1, uint, sampler3d_uint, float3, int3)
DEFINE_INTRINSIC(tex3D, 1, float, sampler3d_float, float3, int3)
DEFINE_INTRINSIC(tex3D, 1, float4, sampler3d_float4, float3, int3)
IMPLEMENT_INTRINSIC_GLSL(tex3D, 0, {
code += "texture(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex3D, 1, {
code += "textureOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex3D, 0, {
if (_shader_model >= 40) { // SM4 and higher use a more object-oriented programming model for textures
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
else
// Integer sampling is not supported until SM6.7, so emulate with a texture fetch
code += "0; { "
"float3 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y, _dimensions.z); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + " * _dimensions, 0)); }";
}
else {
code += "tex3D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex3D, 1, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.Sample(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else
code += "0; { "
"float3 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y, _dimensions.z); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + " * _dimensions, 0), " + id_to_name(args[2].base) + "); }";
}
else {
code += "tex3D(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize)";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex3D, 0, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsMaskNone);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex3D, 1, {
// Non-constant offset operand needs extended capability
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleImplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex1Dgrad(s, coords, ddx, ddy)
// ret tex1Dgrad(s, coords, ddx, ddy, offset)
DEFINE_INTRINSIC(tex1Dgrad, 0, int, sampler1d_int, float, float, float)
DEFINE_INTRINSIC(tex1Dgrad, 0, uint, sampler1d_uint, float, float, float)
DEFINE_INTRINSIC(tex1Dgrad, 0, float, sampler1d_float, float, float, float)
DEFINE_INTRINSIC(tex1Dgrad, 0, float4, sampler1d_float4, float, float, float)
DEFINE_INTRINSIC(tex1Dgrad, 1, int, sampler1d_int, float, float, float, int)
DEFINE_INTRINSIC(tex1Dgrad, 1, uint, sampler1d_uint, float, float, float, int)
DEFINE_INTRINSIC(tex1Dgrad, 1, float, sampler1d_float, float, float, float, int)
DEFINE_INTRINSIC(tex1Dgrad, 1, float4, sampler1d_float4, float, float, float, int)
IMPLEMENT_INTRINSIC_GLSL(tex1Dgrad, 0, {
code += "textureGrad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex1Dgrad, 1, {
code += "textureGradOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dgrad, 0, {
if (_shader_model >= 40) {
code += id_to_name(args[0].base) + ".t.SampleGrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
}
else {
code += "tex1Dgrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dgrad, 1, {
if (_shader_model >= 40) {
code += id_to_name(args[0].base) + ".t.SampleGrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ')';
}
else {
code += "tex1Dgrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[4].base) + " * " + id_to_name(args[0].base) + ".pixelsize, " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dgrad, 0, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsGradMask)
.add(args[2].base)
.add(args[3].base);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dgrad, 1, {
if (!args[4].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsGradMask | (args[4].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
.add(args[2].base)
.add(args[3].base)
.add(args[4].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex2Dgrad(s, coords, ddx, ddy)
// ret tex2Dgrad(s, coords, ddx, ddy, offset)
DEFINE_INTRINSIC(tex2Dgrad, 0, int, sampler2d_int, float2, float2, float2)
DEFINE_INTRINSIC(tex2Dgrad, 0, uint, sampler2d_uint, float2, float2, float2)
DEFINE_INTRINSIC(tex2Dgrad, 0, float, sampler2d_float, float2, float2, float2)
DEFINE_INTRINSIC(tex2Dgrad, 0, float4, sampler2d_float4, float2, float2, float2)
DEFINE_INTRINSIC(tex2Dgrad, 1, int, sampler2d_int, float2, float2, float2, int2)
DEFINE_INTRINSIC(tex2Dgrad, 1, uint, sampler2d_uint, float2, float2, float2, int2)
DEFINE_INTRINSIC(tex2Dgrad, 1, float, sampler2d_float, float2, float2, float2, int2)
DEFINE_INTRINSIC(tex2Dgrad, 1, float4, sampler2d_float4, float2, float2, float2, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2Dgrad, 0, {
code += "textureGrad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex2Dgrad, 1, {
code += "textureGradOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dgrad, 0, {
if (_shader_model >= 40) {
code += id_to_name(args[0].base) + ".t.SampleGrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
}
else {
code += "tex2Dgrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dgrad, 1, {
if (_shader_model >= 40) {
code += id_to_name(args[0].base) + ".t.SampleGrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ')';
}
else {
code += "tex2Dgrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[4].base) + " * " + id_to_name(args[0].base) + ".pixelsize, " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dgrad, 0, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsGradMask)
.add(args[2].base)
.add(args[3].base);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dgrad, 1, {
if (!args[4].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsGradMask | (args[4].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
.add(args[2].base)
.add(args[3].base)
.add(args[4].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex3Dgrad(s, coords, ddx, ddy)
// ret tex3Dgrad(s, coords, ddx, ddy, offset)
DEFINE_INTRINSIC(tex3Dgrad, 0, int, sampler3d_int, float3, float3, float3)
DEFINE_INTRINSIC(tex3Dgrad, 0, uint, sampler3d_uint, float3, float3, float3)
DEFINE_INTRINSIC(tex3Dgrad, 0, float, sampler3d_float, float3, float3, float3)
DEFINE_INTRINSIC(tex3Dgrad, 0, float4, sampler3d_float4, float3, float3, float3)
DEFINE_INTRINSIC(tex3Dgrad, 1, int, sampler3d_int, float3, float3, float3, int2)
DEFINE_INTRINSIC(tex3Dgrad, 1, uint, sampler3d_uint, float3, float3, float3, int2)
DEFINE_INTRINSIC(tex3Dgrad, 1, float, sampler3d_float, float3, float3, float3, int2)
DEFINE_INTRINSIC(tex3Dgrad, 1, float4, sampler3d_float4, float3, float3, float3, int2)
IMPLEMENT_INTRINSIC_GLSL(tex3Dgrad, 0, {
code += "textureGrad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex3Dgrad, 1, {
code += "textureGradOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dgrad, 0, {
if (_shader_model >= 40) {
code += id_to_name(args[0].base) + ".t.SampleGrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
}
else {
code += "tex3Dgrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dgrad, 1, {
if (_shader_model >= 40) {
code += id_to_name(args[0].base) + ".t.SampleGrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ')';
}
else {
code += "tex3Dgrad(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + " + id_to_name(args[4].base) + " * " + id_to_name(args[0].base) + ".pixelsize, " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dgrad, 0, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsGradMask)
.add(args[2].base)
.add(args[3].base);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dgrad, 1, {
if (!args[4].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base)
.add(spv::ImageOperandsGradMask | (args[4].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
.add(args[2].base)
.add(args[3].base)
.add(args[4].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex1Dlod(s, coords)
// ret tex1Dlod(s, coords, offset)
DEFINE_INTRINSIC(tex1Dlod, 0, int, sampler1d_int, float4)
DEFINE_INTRINSIC(tex1Dlod, 0, uint, sampler1d_uint, float4)
DEFINE_INTRINSIC(tex1Dlod, 0, float, sampler1d_float, float4)
DEFINE_INTRINSIC(tex1Dlod, 0, float4, sampler1d_float4, float4)
DEFINE_INTRINSIC(tex1Dlod, 1, int, sampler1d_int, float4, int)
DEFINE_INTRINSIC(tex1Dlod, 1, uint, sampler1d_uint, float4, int)
DEFINE_INTRINSIC(tex1Dlod, 1, float, sampler1d_float, float4, int)
DEFINE_INTRINSIC(tex1Dlod, 1, float4, sampler1d_float4, float4, int)
IMPLEMENT_INTRINSIC_GLSL(tex1Dlod, 0, {
code += "textureLod(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w)";
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex1Dlod, 1, {
code += "textureLodOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dlod, 0, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w)";
else
// Integer sampling is not supported until SM6.7, so emulate with a texture fetch
code += "0; { "
"float _dimensions; float _levels; " +
id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, _dimensions, _levels); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ".x * _dimensions, (int)" + id_to_name(args[1].base) + ".w)); }";
}
else {
code += "tex1Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dlod, 1, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".x, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
else
code += "0; { "
"float _dimensions; float _levels; " +
id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, _dimensions, _levels); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ".x * _dimensions, (int)" + id_to_name(args[1].base) + ".w), " + id_to_name(args[2].base) + "); }";
}
else {
code += "tex1Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + float4(" + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize, 0, 0, 0))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dlod, 0, {
const spv::Id x = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(0); // .x;
const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(3); // .w;
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(x)
.add(spv::ImageOperandsLodMask)
.add(lod);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dlod, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id x = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(0); // .x;
const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(3); // .w;
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(x)
.add(spv::ImageOperandsLodMask | (args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
.add(lod)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex2Dlod(s, coords)
// ret tex2Dlod(s, coords, offset)
DEFINE_INTRINSIC(tex2Dlod, 0, int, sampler2d_int, float4)
DEFINE_INTRINSIC(tex2Dlod, 0, uint, sampler2d_uint, float4)
DEFINE_INTRINSIC(tex2Dlod, 0, float, sampler2d_float, float4)
DEFINE_INTRINSIC(tex2Dlod, 0, float4, sampler2d_float4, float4)
DEFINE_INTRINSIC(tex2Dlod, 1, int, sampler2d_int, float4, int2)
DEFINE_INTRINSIC(tex2Dlod, 1, uint, sampler2d_uint, float4, int2)
DEFINE_INTRINSIC(tex2Dlod, 1, float, sampler2d_float, float4, int2)
DEFINE_INTRINSIC(tex2Dlod, 1, float4, sampler2d_float4, float4, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2Dlod, 0, {
code += "textureLod(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w)";
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex2Dlod, 1, {
code += "textureLodOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dlod, 0, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w)";
else
// Integer sampling is not supported until SM6.7, so emulate with a texture fetch
code += "0; { "
"float2 _dimensions; float _levels; " +
id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, _dimensions.x, _dimensions.y, _levels); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ".xy * _dimensions, (int)" + id_to_name(args[1].base) + ".w)); }";
}
else {
code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dlod, 1, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xy, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
else
code += "0; { "
"float2 _dimensions; float _levels; " +
id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, _dimensions.x, _dimensions.y, _levels); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ".xy * _dimensions, (int)" + id_to_name(args[1].base) + ".w), " + id_to_name(args[2].base) + "); }";
}
else {
code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + float4(" + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize, 0, 0))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dlod, 0, {
const spv::Id xy = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 2, 1 }))
.add(args[1].base)
.add(args[1].base)
.add(0) // .x
.add(1); // .y;
const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(3); // .w;
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(xy)
.add(spv::ImageOperandsLodMask)
.add(lod);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dlod, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id xy = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 2, 1 }))
.add(args[1].base)
.add(args[1].base)
.add(0) // .x
.add(1); // .y;
const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(3); // .w;
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(xy)
.add(spv::ImageOperandsLodMask | (args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
.add(lod)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex3Dlod(s, coords)
// ret tex3Dlod(s, coords, offset)
DEFINE_INTRINSIC(tex3Dlod, 0, int, sampler3d_int, float4)
DEFINE_INTRINSIC(tex3Dlod, 0, uint, sampler3d_uint, float4)
DEFINE_INTRINSIC(tex3Dlod, 0, float, sampler3d_float, float4)
DEFINE_INTRINSIC(tex3Dlod, 0, float4, sampler3d_float4, float4)
DEFINE_INTRINSIC(tex3Dlod, 1, int, sampler3d_int, float4, int2)
DEFINE_INTRINSIC(tex3Dlod, 1, uint, sampler3d_uint, float4, int2)
DEFINE_INTRINSIC(tex3Dlod, 1, float, sampler3d_float, float4, int2)
DEFINE_INTRINSIC(tex3Dlod, 1, float4, sampler3d_float4, float4, int2)
IMPLEMENT_INTRINSIC_GLSL(tex3Dlod, 0, {
code += "textureLod(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w)";
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex3Dlod, 1, {
code += "textureLodOffset(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dlod, 0, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w)";
else
// Integer sampling is not supported until SM6.7, so emulate with a texture fetch
code += "0; { "
"float3 _dimensions; float _levels; " +
id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, _dimensions.x, _dimensions.y, _dimensions.z, _levels); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ".xyz * _dimensions, (int)" + id_to_name(args[1].base) + ".w)); }";
}
else {
code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dlod, 1, {
if (_shader_model >= 40) {
if (res_type.is_floating_point() || _shader_model >= 67)
code += id_to_name(args[0].base) + ".t.SampleLevel(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ".xyz, " + id_to_name(args[1].base) + ".w, " + id_to_name(args[2].base) + ')';
else
code += "0; { "
"float3 _dimensions; float _levels; " +
id_to_name(args[0].base) + ".t.GetDimensions((int)" + id_to_name(args[1].base) + ".w, _dimensions.x, _dimensions.y, _dimensions.z, levels); " +
id_to_name(res) + " = " + id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ".xyz * _dimensions, (int)" + id_to_name(args[1].base) + ".w), " + id_to_name(args[2].base) + "); }";
}
else {
code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + " + float4(" + id_to_name(args[2].base) + " * " + id_to_name(args[0].base) + ".pixelsize, 0))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dlod, 0, {
const spv::Id xyz = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 3, 1 }))
.add(args[1].base)
.add(args[1].base)
.add(0) // .x
.add(1) // .y
.add(2); // .z;
const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(3); // .w;
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(xyz)
.add(spv::ImageOperandsLodMask)
.add(lod);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dlod, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id xyz = add_instruction(spv::OpVectorShuffle, convert_type({ type::t_float, 3, 1 }))
.add(args[1].base)
.add(args[1].base)
.add(0) // .x
.add(1) // .y
.add(2); // .z;
const spv::Id lod = add_instruction(spv::OpCompositeExtract, convert_type({ type::t_float, 1, 1 }))
.add(args[1].base)
.add(3); // .w;
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageSampleExplicitLod, convert_type(res_vector_type))
.add(args[0].base)
.add(xyz)
.add(spv::ImageOperandsLodMask | (args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask))
.add(lod)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex1Dfetch(s, coords)
// ret tex1Dfetch(s, coords, lod)
DEFINE_INTRINSIC(tex1Dfetch, 0, int, sampler1d_int, int)
DEFINE_INTRINSIC(tex1Dfetch, 0, uint, sampler1d_uint, int)
DEFINE_INTRINSIC(tex1Dfetch, 0, float, sampler1d_float, int)
DEFINE_INTRINSIC(tex1Dfetch, 0, float4, sampler1d_float4, int)
DEFINE_INTRINSIC(tex1Dfetch, 1, int, sampler1d_int, int, int)
DEFINE_INTRINSIC(tex1Dfetch, 1, uint, sampler1d_uint, int, int)
DEFINE_INTRINSIC(tex1Dfetch, 1, float, sampler1d_float, int, int)
DEFINE_INTRINSIC(tex1Dfetch, 1, float4, sampler1d_float4, int, int)
DEFINE_INTRINSIC(tex1Dfetch, 2, int, storage1d_int, int)
DEFINE_INTRINSIC(tex1Dfetch, 2, uint, storage1d_uint, int)
DEFINE_INTRINSIC(tex1Dfetch, 2, float, storage1d_float, int)
DEFINE_INTRINSIC(tex1Dfetch, 2, float4, storage1d_float4, int)
IMPLEMENT_INTRINSIC_GLSL(tex1Dfetch, 0, {
code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", 0)";
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex1Dfetch, 1, {
code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_GLSL(tex1Dfetch, 2, {
code += "imageLoad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ")";
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dfetch, 0, {
if (_shader_model >= 40)
code += id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ", 0))";
else {
// SM3 does not have a fetch intrinsic, so emulate it by transforming coordinates into texture space ones
// Also add a half-pixel offset to align texels with pixels
// (coords + 0.5) / size
code += "tex1Dlod(" + id_to_name(args[0].base) + ".s, float4("
"(" + id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize, 0, 0, 0))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dfetch, 1, {
if (_shader_model >= 40)
code += id_to_name(args[0].base) + ".t.Load(int2(" + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + "))";
else {
code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, float4("
"(" + id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize * exp2(" + id_to_name(args[2].base) + "), 0, 0, " + id_to_name(args[2].base) + "))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dfetch, 2, {
code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']';
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dfetch, 0, {
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
.add(image)
.add(args[1].base);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dfetch, 1, {
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
.add(image)
.add(args[1].base)
.add(spv::ImageOperandsLodMask)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dfetch, 2, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageRead, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex2Dfetch(s, coords)
// ret tex2Dfetch(s, coords, lod)
DEFINE_INTRINSIC(tex2Dfetch, 0, int, sampler2d_int, int2)
DEFINE_INTRINSIC(tex2Dfetch, 0, uint, sampler2d_uint, int2)
DEFINE_INTRINSIC(tex2Dfetch, 0, float, sampler2d_float, int2)
DEFINE_INTRINSIC(tex2Dfetch, 0, float4, sampler2d_float4, int2)
DEFINE_INTRINSIC(tex2Dfetch, 1, int, sampler2d_int, int2, int)
DEFINE_INTRINSIC(tex2Dfetch, 1, uint, sampler2d_uint, int2, int)
DEFINE_INTRINSIC(tex2Dfetch, 1, float, sampler2d_float, int2, int)
DEFINE_INTRINSIC(tex2Dfetch, 1, float4, sampler2d_float4, int2, int)
DEFINE_INTRINSIC(tex2Dfetch, 2, int, storage2d_int, int2)
DEFINE_INTRINSIC(tex2Dfetch, 2, uint, storage2d_uint, int2)
DEFINE_INTRINSIC(tex2Dfetch, 2, float, storage2d_float, int2)
DEFINE_INTRINSIC(tex2Dfetch, 2, float4, storage2d_float4, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2Dfetch, 0, {
code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", 0)";
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex2Dfetch, 1, {
code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_GLSL(tex2Dfetch, 2, {
code += "imageLoad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dfetch, 0, {
if (_shader_model >= 40)
code += id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ", 0))";
else {
// SM3 does not have a fetch intrinsic, so emulate it by transforming coordinates into texture space ones
// Also add a half-pixel offset to align texels with pixels
// (coords + 0.5) / size
code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, float4("
"(" + id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize, 0, 0))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dfetch, 1, {
if (_shader_model >= 40)
code += id_to_name(args[0].base) + ".t.Load(int3(" + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + "))";
else {
code += "tex2Dlod(" + id_to_name(args[0].base) + ".s, float4("
"(" + id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize * exp2(" + id_to_name(args[2].base) + "), 0, " + id_to_name(args[2].base) + "))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dfetch, 2, {
if (_shader_model >= 50)
code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']';
else
code += "{}";
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dfetch, 0, {
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
.add(image)
.add(args[1].base);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dfetch, 1, {
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
.add(image)
.add(args[1].base)
.add(spv::ImageOperandsLodMask)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dfetch, 2, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageRead, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex3Dfetch(s, coords)
// ret tex3Dfetch(s, coords, lod)
DEFINE_INTRINSIC(tex3Dfetch, 0, int, sampler3d_int, int3)
DEFINE_INTRINSIC(tex3Dfetch, 0, uint, sampler3d_uint, int3)
DEFINE_INTRINSIC(tex3Dfetch, 0, float, sampler3d_float, int3)
DEFINE_INTRINSIC(tex3Dfetch, 0, float4, sampler3d_float4, int3)
DEFINE_INTRINSIC(tex3Dfetch, 1, int, sampler3d_int, int3, int)
DEFINE_INTRINSIC(tex3Dfetch, 1, uint, sampler3d_uint, int3, int)
DEFINE_INTRINSIC(tex3Dfetch, 1, float, sampler3d_float, int3, int)
DEFINE_INTRINSIC(tex3Dfetch, 1, float4, sampler3d_float4, int3, int)
DEFINE_INTRINSIC(tex3Dfetch, 2, int, storage3d_int, int3)
DEFINE_INTRINSIC(tex3Dfetch, 2, uint, storage3d_uint, int3)
DEFINE_INTRINSIC(tex3Dfetch, 2, float, storage3d_float, int3)
DEFINE_INTRINSIC(tex3Dfetch, 2, float4, storage3d_float4, int3)
IMPLEMENT_INTRINSIC_GLSL(tex3Dfetch, 0, {
code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", 0)";
if (res_type.rows == 1)
code += ".x"; // Collapse last argument from a 4-component vector
})
IMPLEMENT_INTRINSIC_GLSL(tex3Dfetch, 1, {
code += "texelFetch(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_GLSL(tex3Dfetch, 2, {
code += "imageLoad(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ")";
if (res_type.rows == 1)
code += ".x";
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dfetch, 0, {
if (_shader_model >= 40)
code += id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ", 0))";
else {
// SM3 does not have a fetch intrinsic, so emulate it by transforming coordinates into texture space ones
// Also add a half-pixel offset to align texels with pixels
// (coords + 0.5) / size
code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, float4("
"(" + id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize, 0))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dfetch, 1, {
if (_shader_model >= 40)
code += id_to_name(args[0].base) + ".t.Load(int4(" + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + "))";
else {
code += "tex3Dlod(" + id_to_name(args[0].base) + ".s, float4("
"(" + id_to_name(args[1].base) + " + 0.5) * " + id_to_name(args[0].base) + ".pixelsize * exp2(" + id_to_name(args[2].base) + "), " + id_to_name(args[2].base) + "))";
if (res_type.rows == 1)
code += ".x";
}
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dfetch, 2, {
code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']';
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dfetch, 0, {
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
.add(image)
.add(args[1].base);
if (res_type.rows == 1)
// Collapse last argument from a 4-component vector
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dfetch, 1, {
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageFetch, convert_type(res_vector_type))
.add(image)
.add(args[1].base)
.add(spv::ImageOperandsLodMask)
.add(args[2].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dfetch, 2, {
type res_vector_type = res_type;
res_vector_type.rows = 4;
const spv::Id res = add_instruction(spv::OpImageRead, convert_type(res_vector_type))
.add(args[0].base)
.add(args[1].base);
if (res_type.rows == 1)
return
add_instruction(spv::OpCompositeExtract, convert_type(res_type))
.add(res)
.add(0u);
else
return res;
})
// ret tex2DgatherR(s, coords)
// ret tex2DgatherR(s, coords, offset)
// ret tex2DgatherR(s, coords, offset0, offset1, offset2, offset3)
DEFINE_INTRINSIC(tex2DgatherR, 0, float4, sampler2d_float4, float2)
DEFINE_INTRINSIC(tex2DgatherR, 1, float4, sampler2d_float4, float2, int2)
DEFINE_INTRINSIC(tex2DgatherR, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherR, 0, {
code += "textureGather(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", 0)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherR, 1, {
code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + ", 0)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherR, 2, {
code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 0)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherR, 0, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherRed(" + s + ".s, " + id_to_name(args[1].base) + ')';
else if (_shader_model >= 40)
// Emulate texture gather intrinsic by fetching each location separately (SM41 has 'Gather', but that only works on single component texture formats)
// See also https://www.reedbeta.com/blog/texture-gathers-and-coordinate-precision/
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1)).r, " +
s + ".t.Load(_location, int2(1, 1)).r, " +
s + ".t.Load(_location, int2(1, 0)).r, " +
s + ".t.Load(_location, int2(0, 0)).r); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0)).r)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherR, 1, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherRed(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").r, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[2].base) + ").r, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[2].base) + ").r, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[2].base) + ").r); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0)).r)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherR, 2, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherRed(" + s + ".s, " + id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + " - int2(0, 1), " +
id_to_name(args[3].base) + " - int2(1, 1), " +
id_to_name(args[4].base) + " - int2(1, 0), " +
id_to_name(args[5].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").r, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[3].base) + ").r, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[4].base) + ").r, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[5].base) + ").r); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0)).r, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0)).r)";
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherR, 0, {
const spv::Id comp = emit_constant(0u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsMaskNone);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherR, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(0u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherR, 2, {
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(0u);
const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
.add(args[2].base)
.add(args[3].base)
.add(args[4].base)
.add(args[5].base);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsConstOffsetsMask)
.add(offsets);
})
// ret tex2DgatherG(s, coords)
// ret tex2DgatherG(s, coords, offset)
// ret tex2DgatherG(s, coords, offset0, offset1, offset2, offset3)
DEFINE_INTRINSIC(tex2DgatherG, 0, float4, sampler2d_float4, float2)
DEFINE_INTRINSIC(tex2DgatherG, 1, float4, sampler2d_float4, float2, int2)
DEFINE_INTRINSIC(tex2DgatherG, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherG, 0, {
code += "textureGather(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", 1)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherG, 1, {
code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + ", 1)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherG, 2, {
code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 1)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherG, 0, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherGreen(" + id_to_name(args[0].base) + ".s, " + id_to_name(args[1].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1)).g, " +
s + ".t.Load(_location, int2(1, 1)).g, " +
s + ".t.Load(_location, int2(1, 0)).g, " +
s + ".t.Load(_location, int2(0, 0)).g); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0)).g)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherG, 1, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherGreen(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").g, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[2].base) + ").g, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[2].base) + ").g, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[2].base) + ").g); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0)).g)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherG, 2, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherGreen(" + s + ".s, " + id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + " - int2(0, 1), " +
id_to_name(args[3].base) + " - int2(1, 1), " +
id_to_name(args[4].base) + " - int2(1, 0), " +
id_to_name(args[5].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").g, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[3].base) + ").g, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[4].base) + ").g, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[5].base) + ").g); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0)).g, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0)).g)";
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherG, 0, {
const spv::Id comp = emit_constant(1u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsMaskNone);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherG, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(1u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherG, 2, {
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(1u);
const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
.add(args[2].base)
.add(args[3].base)
.add(args[4].base)
.add(args[5].base);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsConstOffsetsMask)
.add(offsets);
})
// ret tex2DgatherB(s, coords)
// ret tex2DgatherB(s, coords, offset)
// ret tex2DgatherB(s, coords, offset0, offset1, offset2, offset3)
DEFINE_INTRINSIC(tex2DgatherB, 0, float4, sampler2d_float4, float2)
DEFINE_INTRINSIC(tex2DgatherB, 1, float4, sampler2d_float4, float2, int2)
DEFINE_INTRINSIC(tex2DgatherB, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherB, 0, {
code += "textureGather(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", 2)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherB, 1, {
code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + ", 2)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherB, 2, {
code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 2)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherB, 0, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherBlue(" + s + ".s, " + id_to_name(args[1].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1)).b, " +
s + ".t.Load(_location, int2(1, 1)).b, " +
s + ".t.Load(_location, int2(1, 0)).b, " +
s + ".t.Load(_location, int2(0, 0)).b); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0)).b)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherB, 1, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherBlue(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").b, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[2].base) + ").b, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[2].base) + ").b, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[2].base) + ").b); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0)).b)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherB, 2, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherBlue(" + s + ".s, " + id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + " - int2(0, 1), " +
id_to_name(args[3].base) + " - int2(1, 1), " +
id_to_name(args[4].base) + " - int2(1, 0), " +
id_to_name(args[5].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").b, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[3].base) + ").b, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[4].base) + ").b, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[5].base) + ").b); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0)).b, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0)).b)";
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherB, 0, {
const spv::Id comp = emit_constant(2u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsMaskNone);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherB, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(2u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherB, 2, {
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(2u);
const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
.add(args[2].base)
.add(args[3].base)
.add(args[4].base)
.add(args[5].base);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsConstOffsetsMask)
.add(offsets);
})
// ret tex2DgatherA(s, coords)
// ret tex2DgatherA(s, coords, offset)
// ret tex2DgatherA(s, coords, offset0, offset1, offset2, offset3)
DEFINE_INTRINSIC(tex2DgatherA, 0, float4, sampler2d_float4, float2)
DEFINE_INTRINSIC(tex2DgatherA, 1, float4, sampler2d_float4, float2, int2)
DEFINE_INTRINSIC(tex2DgatherA, 2, float4, sampler2d_float4, float2, int2, int2, int2, int2)
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherA, 0, {
code += "textureGather(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", 3)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherA, 1, {
code += "textureGatherOffset(" + id_to_name(args[0].base) + ", " +
id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + ", 3)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2DgatherA, 2, {
code += "textureGatherOffsets(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " +
"ivec2[]( " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(args[4].base) + ", " + id_to_name(args[5].base) + "), 3)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherA, 0, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherAlpha(" + s + ".s, " + id_to_name(args[1].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1)).a, " +
s + ".t.Load(_location, int2(1, 1)).a, " +
s + ".t.Load(_location, int2(1, 0)).a, " +
s + ".t.Load(_location, int2(0, 0)).a); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 1) * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 1) * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(1, 0) * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + float2(0, 0) * " + s + ".pixelsize, 0, 0)).a)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherA, 1, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherAlpha(" + s + ".s, " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").a, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[2].base) + ").a, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[2].base) + ").a, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[2].base) + ").a); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 1)) * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 1)) * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(1, 0)) * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + " + float2(0, 0)) * " + s + ".pixelsize, 0, 0)).a)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2DgatherA, 2, {
const std::string s = id_to_name(args[0].base);
if (_shader_model >= 50)
code += s + ".t.GatherAlpha(" + s + ".s, " + id_to_name(args[1].base) + ", " +
id_to_name(args[2].base) + " - int2(0, 1), " +
id_to_name(args[3].base) + " - int2(1, 1), " +
id_to_name(args[4].base) + " - int2(1, 0), " +
id_to_name(args[5].base) + ')';
else if (_shader_model >= 40)
code += "0; { "
"float2 _dimensions; " +
id_to_name(args[0].base) + ".t.GetDimensions(_dimensions.x, _dimensions.y); "
"int3 _location = int3(" + id_to_name(args[1].base) + " * _dimensions - 0.5 + 1.0 / 512.0, 0); " +
id_to_name(res) + " = float4(" +
s + ".t.Load(_location, int2(0, 1) + " + id_to_name(args[2].base) + ").a, " +
s + ".t.Load(_location, int2(1, 1) + " + id_to_name(args[3].base) + ").a, " +
s + ".t.Load(_location, int2(1, 0) + " + id_to_name(args[4].base) + ").a, " +
s + ".t.Load(_location, int2(0, 0) + " + id_to_name(args[5].base) + ").a); }";
else
code += "float4("
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[2].base) + ") * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[3].base) + ") * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[4].base) + ") * " + s + ".pixelsize, 0, 0)).a, "
"tex2Dlod(" + s + ".s, float4(" + id_to_name(args[1].base) + " + (" + id_to_name(args[5].base) + ") * " + s + ".pixelsize, 0, 0)).a)";
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherA, 0, {
const spv::Id comp = emit_constant(3u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsMaskNone);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherA, 1, {
if (!args[2].is_constant)
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(3u);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(args[2].is_constant ? spv::ImageOperandsConstOffsetMask : spv::ImageOperandsOffsetMask)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2DgatherA, 2, {
add_capability(spv::CapabilityImageGatherExtended);
const spv::Id comp = emit_constant(3u);
const spv::Id offsets = add_instruction(spv::OpConstantComposite, convert_type({ reshadefx::type::t_int, 2, 1, 0, 4 }), _types_and_constants)
.add(args[2].base)
.add(args[3].base)
.add(args[4].base)
.add(args[5].base);
return
add_instruction(spv::OpImageGather, convert_type(res_type))
.add(args[0].base)
.add(args[1].base)
.add(comp)
.add(spv::ImageOperandsConstOffsetsMask)
.add(offsets);
})
// tex1Dstore(s, coords, value)
DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_int, int, int)
DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_uint, int, uint)
DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_float, int, float)
DEFINE_INTRINSIC(tex1Dstore, 0, void, storage1d_float4, int, float4)
IMPLEMENT_INTRINSIC_GLSL(tex1Dstore, 0, {
code += "imageStore(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", ";
if (args[2].type.rows == 1)
code += '(';
code += id_to_name(args[2].base);
if (args[2].type.rows == 1)
code += ").xxxx"; // Expand last argument to a 4-component vector
code += ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dstore, 0, {
if (_shader_model >= 50)
code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + "] = " + id_to_name(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dstore, 0, {
spv::Id data = args[2].base;
if (args[2].type.rows == 1)
{
// Expand last argument to a 4-component vector
auto comp_type = args[2].type;
comp_type.rows = 4;
data = add_instruction(spv::OpCompositeConstruct, convert_type(comp_type))
.add(data)
.add(data)
.add(data)
.add(data);
}
add_instruction_without_result(spv::OpImageWrite)
.add(args[0].base)
.add(args[1].base)
.add(data);
return 0;
})
// tex2Dstore(s, coords, value)
DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_int, int2, int)
DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_uint, int2, uint)
DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_float, int2, float)
DEFINE_INTRINSIC(tex2Dstore, 0, void, storage2d_float4, int2, float4)
IMPLEMENT_INTRINSIC_GLSL(tex2Dstore, 0, {
code += "imageStore(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", ";
if (args[2].type.rows == 1)
code += '(';
code += id_to_name(args[2].base);
if (args[2].type.rows == 1)
code += ").xxxx"; // Expand last argument to a 4-component vector
code += ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dstore, 0, {
if (_shader_model >= 50)
code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + "] = " + id_to_name(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dstore, 0, {
spv::Id data = args[2].base;
if (args[2].type.rows == 1)
{
// Expand last argument to a 4-component vector
auto comp_type = args[2].type;
comp_type.rows = 4;
data = add_instruction(spv::OpCompositeConstruct, convert_type(comp_type))
.add(data)
.add(data)
.add(data)
.add(data);
}
add_instruction_without_result(spv::OpImageWrite)
.add(args[0].base)
.add(args[1].base)
.add(data);
return 0;
})
// tex3Dstore(s, coords, value)
DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_int, int3, int)
DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_uint, int3, uint)
DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_float, int3, float)
DEFINE_INTRINSIC(tex3Dstore, 0, void, storage3d_float4, int3, float4)
IMPLEMENT_INTRINSIC_GLSL(tex3Dstore, 0, {
code += "imageStore(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", ";
if (args[2].type.rows == 1)
code += '(';
code += id_to_name(args[2].base);
if (args[2].type.rows == 1)
code += ").xxxx"; // Expand last argument to a 4-component vector
code += ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dstore, 0, {
if (_shader_model >= 50)
code += id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + "] = " + id_to_name(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dstore, 0, {
spv::Id data = args[2].base;
if (args[2].type.rows == 1)
{
// Expand last argument to a 4-component vector
auto comp_type = args[2].type;
comp_type.rows = 4;
data = add_instruction(spv::OpCompositeConstruct, convert_type(comp_type))
.add(data)
.add(data)
.add(data)
.add(data);
}
add_instruction_without_result(spv::OpImageWrite)
.add(args[0].base)
.add(args[1].base)
.add(data);
return 0;
})
// ret tex1Dsize(s)
// ret tex1Dsize(s, lod)
DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_int)
DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_uint)
DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_float)
DEFINE_INTRINSIC(tex1Dsize, 0, int, sampler1d_float4)
DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_int, int)
DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_uint, int)
DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_float, int)
DEFINE_INTRINSIC(tex1Dsize, 1, int, sampler1d_float4, int)
DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_int)
DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_uint)
DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_float)
DEFINE_INTRINSIC(tex1Dsize, 2, int, storage1d_float4)
IMPLEMENT_INTRINSIC_GLSL(tex1Dsize, 0, {
code += "textureSize(" + id_to_name(args[0].base) + ", 0)";
})
IMPLEMENT_INTRINSIC_GLSL(tex1Dsize, 1, {
code += "textureSize(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(tex1Dsize, 2, {
code += "imageSize(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dsize, 0, {
if (_shader_model >= 40)
code += "0; " + id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(res) + ')';
else
code += "int(1.0 / " + id_to_name(args[0].base) + ".pixelsize)";
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dsize, 1, {
if (_shader_model >= 40)
code += "0; { uint _levels; " + // Don't need the number of levels out value, so route that to a dummy variable
id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(args[1].base) + ", " + id_to_name(res) + ", _levels); }";
else
code += "int(1.0 / " + id_to_name(args[0].base) + ".pixelsize) / exp2(" + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex1Dsize, 2, {
if (_shader_model >= 50)
code += "0; " + id_to_name(args[0].base) + ".GetDimensions(" + id_to_name(res) + ')';
else
code += "0"; // Only supported on SM5+
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dsize, 0, {
add_capability(spv::CapabilityImageQuery);
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
const spv::Id level = emit_constant(0u);
return
add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
.add(image)
.add(level);
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dsize, 1, {
add_capability(spv::CapabilityImageQuery);
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
return
add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
.add(image)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex1Dsize, 2, {
add_capability(spv::CapabilityImageQuery);
return
add_instruction(spv::OpImageQuerySize, convert_type(res_type))
.add(args[0].base);
})
// ret tex2Dsize(s)
// ret tex2Dsize(s, lod)
DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_int)
DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_uint)
DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_float)
DEFINE_INTRINSIC(tex2Dsize, 0, int2, sampler2d_float4)
DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_int, int)
DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_uint, int)
DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_float, int)
DEFINE_INTRINSIC(tex2Dsize, 1, int2, sampler2d_float4, int)
DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_int)
DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_uint)
DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_float)
DEFINE_INTRINSIC(tex2Dsize, 2, int2, storage2d_float4)
IMPLEMENT_INTRINSIC_GLSL(tex2Dsize, 0, {
code += "textureSize(" + id_to_name(args[0].base) + ", 0)";
})
IMPLEMENT_INTRINSIC_GLSL(tex2Dsize, 1, {
code += "textureSize(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(tex2Dsize, 2, {
code += "imageSize(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dsize, 0, {
if (_shader_model >= 40)
code += "0; " + id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y)";
else
code += "int2(1.0 / " + id_to_name(args[0].base) + ".pixelsize)";
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dsize, 1, {
if (_shader_model >= 40)
code += "0; { uint _levels; " + // Don't need the number of levels out value, so route that to a dummy variable
id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(args[1].base) + ", " + id_to_name(res) + ".x, " + id_to_name(res) + ".y, _levels); }";
else
code += "int2(1.0 / " + id_to_name(args[0].base) + ".pixelsize) / exp2(" + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex2Dsize, 2, {
if (_shader_model >= 50)
code += "0; " + id_to_name(args[0].base) + ".GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y)";
else
code += "int2(0, 0)"; // Only supported on SM5+
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dsize, 0, {
add_capability(spv::CapabilityImageQuery);
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
const spv::Id level = emit_constant(0u);
return
add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
.add(image)
.add(level);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dsize, 1, {
add_capability(spv::CapabilityImageQuery);
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
return
add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
.add(image)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex2Dsize, 2, {
add_capability(spv::CapabilityImageQuery);
return
add_instruction(spv::OpImageQuerySize, convert_type(res_type))
.add(args[0].base);
})
// ret tex3Dsize(s)
// ret tex3Dsize(s, lod)
DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_int)
DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_uint)
DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_float)
DEFINE_INTRINSIC(tex3Dsize, 0, int3, sampler3d_float4)
DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_int, int)
DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_uint, int)
DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_float, int)
DEFINE_INTRINSIC(tex3Dsize, 1, int3, sampler3d_float4, int)
DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_int)
DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_uint)
DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_float)
DEFINE_INTRINSIC(tex3Dsize, 2, int3, storage3d_float4)
IMPLEMENT_INTRINSIC_GLSL(tex3Dsize, 0, {
code += "textureSize(" + id_to_name(args[0].base) + ", 0)";
})
IMPLEMENT_INTRINSIC_GLSL(tex3Dsize, 1, {
code += "textureSize(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(tex3Dsize, 2, {
code += "imageSize(" + id_to_name(args[0].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dsize, 0, {
if (_shader_model >= 40)
code += "0; " + id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y, " + id_to_name(res) + ".z)";
else
code += "int3(1.0 / " + id_to_name(args[0].base) + ".pixelsize)";
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dsize, 1, {
if (_shader_model >= 40)
code += "0; { uint _levels; " + // Don't need the number of levels out value, so route that to a dummy variable
id_to_name(args[0].base) + ".t.GetDimensions(" + id_to_name(args[1].base) + ", " + id_to_name(res) + ".x, " + id_to_name(res) + ".y, " + id_to_name(res) + ".z, _levels); }";
else
code += "int3(1.0 / " + id_to_name(args[0].base) + ".pixelsize) / exp2(" + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(tex3Dsize, 2, {
if (_shader_model >= 50)
code += "0; " + id_to_name(args[0].base) + ".GetDimensions(" + id_to_name(res) + ".x, " + id_to_name(res) + ".y, " + id_to_name(res) + ".z)";
else
code += "int3(0, 0, 0)"; // Only supported on SM5+
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dsize, 0, {
add_capability(spv::CapabilityImageQuery);
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
const spv::Id level = emit_constant(0u);
return
add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
.add(image)
.add(level);
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dsize, 1, {
add_capability(spv::CapabilityImageQuery);
const spv::Id image = add_instruction(spv::OpImage, convert_image_type(args[0].type))
.add(args[0].base);
return
add_instruction(spv::OpImageQuerySizeLod, convert_type(res_type))
.add(image)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(tex3Dsize, 2, {
add_capability(spv::CapabilityImageQuery);
return
add_instruction(spv::OpImageQuerySize, convert_type(res_type))
.add(args[0].base);
})
// barrier()
DEFINE_INTRINSIC(barrier, 0, void)
IMPLEMENT_INTRINSIC_GLSL(barrier, 0, {
code += "barrier()";
})
IMPLEMENT_INTRINSIC_HLSL(barrier, 0, {
if (_shader_model >= 50)
code += "GroupMemoryBarrierWithGroupSync()";
})
IMPLEMENT_INTRINSIC_SPIRV(barrier, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeWorkgroup);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsWorkgroupMemoryMask | spv::MemorySemanticsAcquireReleaseMask);
add_instruction_without_result(spv::OpControlBarrier)
.add(mem_scope) // Execution scope
.add(mem_scope)
.add(mem_semantics);
return 0;
})
// memoryBarrier()
DEFINE_INTRINSIC(memoryBarrier, 0, void)
IMPLEMENT_INTRINSIC_GLSL(memoryBarrier, 0, {
code += "memoryBarrier()";
})
IMPLEMENT_INTRINSIC_HLSL(memoryBarrier, 0, {
if (_shader_model >= 50)
code += "AllMemoryBarrier()";
})
IMPLEMENT_INTRINSIC_SPIRV(memoryBarrier, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsImageMemoryMask | spv::MemorySemanticsUniformMemoryMask | spv::MemorySemanticsWorkgroupMemoryMask | spv::MemorySemanticsAcquireReleaseMask);
add_instruction_without_result(spv::OpMemoryBarrier)
.add(mem_scope)
.add(mem_semantics);
return 0;
})
// groupMemoryBarrier()
DEFINE_INTRINSIC(groupMemoryBarrier, 0, void)
IMPLEMENT_INTRINSIC_GLSL(groupMemoryBarrier, 0, {
code += "groupMemoryBarrier()";
})
IMPLEMENT_INTRINSIC_HLSL(groupMemoryBarrier, 0, {
if (_shader_model >= 50)
code += "GroupMemoryBarrier()";
})
IMPLEMENT_INTRINSIC_SPIRV(groupMemoryBarrier, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeWorkgroup);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsWorkgroupMemoryMask | spv::MemorySemanticsAcquireReleaseMask);
add_instruction_without_result(spv::OpMemoryBarrier)
.add(mem_scope)
.add(mem_semantics);
return 0;
})
// ret atomicAdd(inout mem, data)
DEFINE_INTRINSIC(atomicAdd, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicAdd, 0, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicAdd, 0, {
code += "atomicAdd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicAdd, 0, {
if (_shader_model >= 50)
code += "0; InterlockedAdd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " += " + id_to_name(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicAdd, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicIAdd, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicAdd(s, coords, data)
DEFINE_INTRINSIC(atomicAdd, 1, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicAdd, 1, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicAdd, 1, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicAdd, 1, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicAdd, 1, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicAdd, 1, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicAdd, 1, {
code += "imageAtomicAdd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicAdd, 1, {
if (_shader_model >= 50)
code += "0; InterlockedAdd(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicAdd, 1, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicIAdd, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicAnd(inout mem, data)
DEFINE_INTRINSIC(atomicAnd, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicAnd, 0, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicAnd, 0, {
code += "atomicAnd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicAnd, 0, {
if (_shader_model >= 50)
code += "0; InterlockedAnd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " &= " + id_to_name(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicAnd, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicAnd, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicAnd(s, coords, data)
DEFINE_INTRINSIC(atomicAnd, 1, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicAnd, 1, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicAnd, 1, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicAnd, 1, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicAnd, 1, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicAnd, 1, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicAnd, 1, {
code += "imageAtomicAnd(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicAnd, 1, {
if (_shader_model >= 50)
code += "InterlockedAnd(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicAnd, 1, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicAnd, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicOr(inout mem, data)
DEFINE_INTRINSIC(atomicOr, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicOr, 0, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicOr, 0, {
code += "atomicOr(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicOr, 0, {
if (_shader_model >= 50)
code += "0; InterlockedOr(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " |= " + id_to_name(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicOr, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicOr, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicOr(s, coords, data)
DEFINE_INTRINSIC(atomicOr, 1, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicOr, 1, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicOr, 1, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicOr, 1, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicOr, 1, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicOr, 1, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicOr, 1, {
code += "imageAtomicOr(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicOr, 1, {
if (_shader_model >= 50)
code += "0; InterlockedOr(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicOr, 1, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicOr, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicXor(inout mem, data)
DEFINE_INTRINSIC(atomicXor, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicXor, 0, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicXor, 0, {
code += "atomicXor(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicXor, 0, {
if (_shader_model >= 50)
code += "0; InterlockedXor(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " ^= " + id_to_name(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicXor, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicXor, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicXor(s, coords, data)
DEFINE_INTRINSIC(atomicXor, 1, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicXor, 1, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicXor, 1, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicXor, 1, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicXor, 1, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicXor, 1, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicXor, 1, {
code += "imageAtomicXor(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicXor, 1, {
if (_shader_model >= 50)
code += "0; InterlockedXor(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicXor, 1, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicXor, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicMin(inout mem, data)
DEFINE_INTRINSIC(atomicMin, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicMin, 1, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicMin, 0, {
code += "atomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(atomicMin, 1, {
code += "atomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMin, 0, {
if (_shader_model >= 50)
code += "0; InterlockedMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMin, 1, {
if (_shader_model >= 50)
code += "0; InterlockedMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = min(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicSMin, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 1, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicUMin, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicMin(s, coords, data)
DEFINE_INTRINSIC(atomicMin, 2, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicMin, 2, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicMin, 2, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicMin, 3, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicMin, 3, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicMin, 3, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicMin, 2, {
code += "imageAtomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(atomicMin, 3, {
code += "imageAtomicMin(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMin, 2, {
if (_shader_model >= 50)
code += "0; InterlockedMin(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMin, 3, {
if (_shader_model >= 50)
code += "0; InterlockedMin(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 2, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicSMin, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMin, 3, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicUMin, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicMax(inout mem, data)
DEFINE_INTRINSIC(atomicMax, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicMax, 1, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicMax, 0, {
code += "atomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(atomicMax, 1, {
code += "atomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMax, 0, {
if (_shader_model >= 50)
code += "0; InterlockedMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMax, 1, {
if (_shader_model >= 50)
code += "0; InterlockedMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = max(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicSMax, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 1, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicUMax, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicMax(s, coords, data)
DEFINE_INTRINSIC(atomicMax, 2, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicMax, 2, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicMax, 2, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicMax, 3, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicMax, 3, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicMax, 3, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicMax, 2, {
code += "imageAtomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_GLSL(atomicMax, 3, {
code += "imageAtomicMax(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMax, 2, {
if (_shader_model >= 50)
code += "0; InterlockedMax(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicMax, 3, {
if (_shader_model >= 50)
code += "0; InterlockedMax(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 2, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicSMax, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicMax, 3, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicUMax, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicExchange(inout mem, data)
DEFINE_INTRINSIC(atomicExchange, 0, int, inout_int, int)
DEFINE_INTRINSIC(atomicExchange, 0, uint, inout_uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicExchange, 0, {
code += "atomicExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicExchange, 0, {
if (_shader_model >= 50)
code += "0; InterlockedExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; " + id_to_name(args[0].base) + " = " + id_to_name(args[1].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicExchange, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicExchange, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(args[1].base);
})
// ret atomicExchange(s, coords, data)
DEFINE_INTRINSIC(atomicExchange, 1, int, inout_storage1d_int, int, int)
DEFINE_INTRINSIC(atomicExchange, 1, int, inout_storage2d_int, int2, int)
DEFINE_INTRINSIC(atomicExchange, 1, int, inout_storage3d_int, int3, int)
DEFINE_INTRINSIC(atomicExchange, 1, uint, inout_storage1d_uint, int, uint)
DEFINE_INTRINSIC(atomicExchange, 1, uint, inout_storage2d_uint, int2, uint)
DEFINE_INTRINSIC(atomicExchange, 1, uint, inout_storage3d_uint, int3, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicExchange, 1, {
code += "imageAtomicExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicExchange, 1, {
if (_shader_model >= 50)
code += "0; InterlockedExchange(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicExchange, 1, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicExchange, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(args[2].base);
})
// ret atomicCompareExchange(inout mem, compare, data)
DEFINE_INTRINSIC(atomicCompareExchange, 0, int, inout_int, int, int)
DEFINE_INTRINSIC(atomicCompareExchange, 0, uint, inout_uint, uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicCompareExchange, 0, {
code += "atomicCompSwap(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicCompareExchange, 0, {
if (_shader_model >= 50)
code += "0; InterlockedCompareExchange(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(res) + ')';
else
code += id_to_name(args[0].base) + "; if (" + id_to_name(args[0].base) + " == " + id_to_name(args[1].base) + ") " + id_to_name(args[0].base) + " = " + id_to_name(args[2].base);
})
IMPLEMENT_INTRINSIC_SPIRV(atomicCompareExchange, 0, {
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicCompareExchange, convert_type(res_type))
.add(args[0].base)
.add(mem_scope)
.add(mem_semantics)
.add(mem_semantics)
.add(args[2].base)
.add(args[1].base);
})
// ret atomicCompareExchange(s, coords, compare, data)
DEFINE_INTRINSIC(atomicCompareExchange, 1, int, inout_storage1d_int, int, int, int)
DEFINE_INTRINSIC(atomicCompareExchange, 1, int, inout_storage2d_int, int2, int, int)
DEFINE_INTRINSIC(atomicCompareExchange, 1, int, inout_storage3d_int, int3, int, int)
DEFINE_INTRINSIC(atomicCompareExchange, 1, uint, inout_storage1d_uint, int, uint, uint)
DEFINE_INTRINSIC(atomicCompareExchange, 1, uint, inout_storage2d_uint, int2, uint, uint)
DEFINE_INTRINSIC(atomicCompareExchange, 1, uint, inout_storage3d_uint, int3, uint, uint)
IMPLEMENT_INTRINSIC_GLSL(atomicCompareExchange, 1, {
code += "imageAtomicCompSwap(" + id_to_name(args[0].base) + ", " + id_to_name(args[1].base) + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ')';
})
IMPLEMENT_INTRINSIC_HLSL(atomicCompareExchange, 1, {
if (_shader_model >= 50)
code += "0; InterlockedCompareExchange(" + id_to_name(args[0].base) + '[' + id_to_name(args[1].base) + ']' + ", " + id_to_name(args[2].base) + ", " + id_to_name(args[3].base) + ", " + id_to_name(res) + ')';
})
IMPLEMENT_INTRINSIC_SPIRV(atomicCompareExchange, 1, {
const spv::Id ms_sample = emit_constant(0u);
const spv::Id texel = add_instruction(spv::OpImageTexelPointer, convert_type(res_type, true, spv::StorageClassImage))
.add(args[0].base)
.add(args[1].base)
.add(ms_sample);
const spv::Id mem_scope = emit_constant(spv::ScopeDevice);
const spv::Id mem_semantics = emit_constant(spv::MemorySemanticsMaskNone);
return
add_instruction(spv::OpAtomicCompareExchange, convert_type(res_type))
.add(texel)
.add(mem_scope)
.add(mem_semantics)
.add(mem_semantics)
.add(args[3].base)
.add(args[2].base);
})
#undef DEFINE_INTRINSIC
#undef IMPLEMENT_INTRINSIC_GLSL
#undef IMPLEMENT_INTRINSIC_HLSL
#undef IMPLEMENT_INTRINSIC_SPIRV