Begin adding float16_t support to GLSL.

This commit is contained in:
Hans-Kristian Arntzen 2018-03-06 15:32:26 +01:00
Родитель b0a2de5b63
Коммит 91f85d3412
4 изменённых файлов: 141 добавлений и 3 удалений

Просмотреть файл

@ -263,6 +263,7 @@ struct SPIRType : IVariant
Int64,
UInt64,
AtomicCounter,
Half,
Float,
Double,
Struct,
@ -751,6 +752,58 @@ struct SPIRConstant : IVariant
}
};
static inline float f16_to_f32(uint16_t u16_value)
{
// Based on the GLM implementation.
int s = (u16_value >> 15) & 0x1;
int e = (u16_value >> 10) & 0x1f;
int m = (u16_value >> 0) & 0x3ff;
union
{
float f32;
uint32_t u32;
} u;
if (e == 0)
{
if (m == 0)
{
u.u32 = uint32_t(s) << 31;
return u.f32;
}
else
{
while ((m & 0x400) == 0)
{
m <<= 1;
e--;
}
e++;
m &= ~0x400;
}
}
else if (e == 31)
{
if (m == 0)
{
u.u32 = (uint32_t(s) << 31) | 0x7f800000u;
return u.f32;
}
else
{
u.u32 = (uint32_t(s) << 31) | 0x7f800000u | (m << 13);
return u.f32;
}
}
e += 127 - 15;
m <<= 13;
u.u32 = (uint32_t(s) << 31) | (e << 23) | m;
return u.f32;
}
inline uint32_t specialization_constant_id(uint32_t col, uint32_t row) const
{
return m.c[col].id[row];
@ -766,6 +819,16 @@ struct SPIRConstant : IVariant
return m.c[col].r[row].u32;
}
inline uint16_t scalar_u16(uint32_t col = 0, uint32_t row = 0) const
{
return uint16_t(m.c[col].r[row].u32 & 0xffffu);
}
inline float scalar_f16(uint32_t col = 0, uint32_t row = 0) const
{
return f16_to_f32(scalar_u16(col, row));
}
inline float scalar_f32(uint32_t col = 0, uint32_t row = 0) const
{
return m.c[col].r[row].f32;

Просмотреть файл

@ -1565,7 +1565,14 @@ void Compiler::parse(const Instruction &instruction)
uint32_t id = ops[0];
uint32_t width = ops[1];
auto &type = set<SPIRType>(id);
type.basetype = width > 32 ? SPIRType::Double : SPIRType::Float;
if (width == 64)
type.basetype = SPIRType::Double;
else if (width == 32)
type.basetype = SPIRType::Float;
else if (width == 16)
type.basetype = SPIRType::Half;
else
SPIRV_CROSS_THROW("Unrecognized bit-width of floating point type.");
type.width = width;
break;
}

Просмотреть файл

@ -26,6 +26,13 @@ using namespace spv;
using namespace spirv_cross;
using namespace std;
static bool type_is_floating_point(const SPIRType &type)
{
return type.basetype == SPIRType::Half ||
type.basetype == SPIRType::Float ||
type.basetype == SPIRType::Double;
}
static bool packing_is_vec4_padded(BufferPackingStandard packing)
{
switch (packing)
@ -319,6 +326,9 @@ void CompilerGLSL::find_static_extensions()
if (!options.es)
require_extension("GL_ARB_gpu_shader_int64");
}
if (type.basetype == SPIRType::Half)
require_extension("GL_AMD_gpu_shader_half_float");
}
}
@ -2567,6 +2577,29 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c)
#pragma warning(disable : 4996)
#endif
string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
{
string res;
float float_value = c.scalar_f16(col, row);
if (std::isnan(float_value) || std::isinf(float_value))
{
// There is no uintBitsToFloat for 16-bit, so have to rely on legacy fallback here.
if (float_value == numeric_limits<float>::infinity())
res = "(1.0hf / 0.0hf)";
else if (float_value == -numeric_limits<float>::infinity())
res = "(-1.0hf / 0.0hf)";
else if (std::isnan(float_value))
res = "(0.0hf / 0.0hf)";
else
SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
}
else
res = convert_to_string(float_value) + "hf";
return res;
}
string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
{
string res;
@ -2712,7 +2745,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Double)
if (!type_is_floating_point(type))
{
// Cannot swizzle literal integers as a special case.
swizzle_splat = false;
@ -2766,6 +2799,28 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
switch (type.basetype)
{
case SPIRType::Half:
if (splat || swizzle_splat)
{
res += convert_half_to_string(c, vector, 0);
if (swizzle_splat)
res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
}
else
{
for (uint32_t i = 0; i < c.vector_size(); i++)
{
if (options.vulkan_semantics && c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
res += to_name(c.specialization_constant_id(vector, i));
else
res += convert_half_to_string(c, vector, i);
if (i + 1 < c.vector_size())
res += ", ";
}
}
break;
case SPIRType::Float:
if (splat || swizzle_splat)
{
@ -3310,6 +3365,10 @@ bool CompilerGLSL::to_trivial_mix_op(const SPIRType &type, string &op, uint32_t
ret = cleft->scalar() == 0 && cright->scalar() == 1;
break;
case SPIRType::Half:
ret = cleft->scalar_f16() == 0.0f && cright->scalar_f16() == 1.0f;
break;
case SPIRType::Float:
ret = cleft->scalar_f32() == 0.0f && cright->scalar_f32() == 1.0f;
break;
@ -5716,7 +5775,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
bool swizzle_splat = in_type.vecsize == 1 && in_type.columns == 1 && backend.can_swizzle_scalar;
if (ids[elems[0]].get_type() == TypeConstant &&
(in_type.basetype != SPIRType::Float && in_type.basetype != SPIRType::Double))
!type_is_floating_point(in_type))
{
// Cannot swizzle literal integers as a special case.
swizzle_splat = false;
@ -7724,6 +7783,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
return backend.basic_uint_type;
case SPIRType::AtomicCounter:
return "atomic_uint";
case SPIRType::Half:
return "float16_t";
case SPIRType::Float:
return "float";
case SPIRType::Double:
@ -7746,6 +7807,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
return join("ivec", type.vecsize);
case SPIRType::UInt:
return join("uvec", type.vecsize);
case SPIRType::Half:
return join("f16vec", type.vecsize);
case SPIRType::Float:
return join("vec", type.vecsize);
case SPIRType::Double:
@ -7768,6 +7831,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
return join("imat", type.vecsize);
case SPIRType::UInt:
return join("umat", type.vecsize);
case SPIRType::Half:
return join("f16mat", type.vecsize);
case SPIRType::Float:
return join("mat", type.vecsize);
case SPIRType::Double:
@ -7787,6 +7852,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id)
return join("imat", type.columns, "x", type.vecsize);
case SPIRType::UInt:
return join("umat", type.columns, "x", type.vecsize);
case SPIRType::Half:
return join("f16mat", type.columns, "x", type.vecsize);
case SPIRType::Float:
return join("mat", type.columns, "x", type.vecsize);
case SPIRType::Double:

Просмотреть файл

@ -528,6 +528,7 @@ protected:
const Instruction *get_next_instruction_in_block(const Instruction &instr);
static uint32_t mask_relevant_memory_semantics(uint32_t semantics);
std::string convert_half_to_string(const SPIRConstant &value, uint32_t col, uint32_t row);
std::string convert_float_to_string(const SPIRConstant &value, uint32_t col, uint32_t row);
std::string convert_double_to_string(const SPIRConstant &value, uint32_t col, uint32_t row);