Support special float constants (NaN/Inf).

This commit is contained in:
Hans-Kristian Arntzen 2018-02-23 13:06:20 +01:00
Родитель 3f64f56037
Коммит 047ad7df0f
15 изменённых файлов: 327 добавлений и 17 удалений

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

@ -0,0 +1,19 @@
static float3 FragColor;
struct SPIRV_Cross_Output
{
float3 FragColor : SV_Target0;
};
void frag_main()
{
FragColor = float3(asfloat(0x7f800000u), asfloat(0xff800000u), asfloat(0xffc00000u));
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

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

@ -0,0 +1,17 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float3 FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.FragColor = float3(as_type<float>(0x7f800000u), as_type<float>(0xff800000u), as_type<float>(0xffc00000u));
return out;
}

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

@ -0,0 +1,11 @@
#version 450
#extension GL_ARB_gpu_shader_int64 : require
layout(location = 0) out vec3 FragColor;
layout(location = 0) flat in double vTmp;
void main()
{
FragColor = vec3(dvec3(uint64BitsToDouble(0x7ff0000000000000ul), uint64BitsToDouble(0xfff0000000000000ul), uint64BitsToDouble(0xfff8000000000000ul)) + dvec3(vTmp));
}

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

@ -0,0 +1,11 @@
#version 310 es
precision mediump float;
precision highp int;
layout(location = 0) out highp vec3 FragColor;
void main()
{
FragColor = vec3(uintBitsToFloat(0x7f800000u), uintBitsToFloat(0xff800000u), uintBitsToFloat(0xffc00000u));
}

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

@ -0,0 +1,19 @@
static float3 FragColor;
struct SPIRV_Cross_Output
{
float3 FragColor : SV_Target0;
};
void frag_main()
{
FragColor = float3(asfloat(0x7f800000u), asfloat(0xff800000u), asfloat(0xffc00000u));
}
SPIRV_Cross_Output main()
{
frag_main();
SPIRV_Cross_Output stage_output;
stage_output.FragColor = FragColor;
return stage_output;
}

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

@ -0,0 +1,17 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float3 FragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.FragColor = float3(as_type<float>(0x7f800000u), as_type<float>(0xff800000u), as_type<float>(0xffc00000u));
return out;
}

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

@ -0,0 +1,11 @@
#version 450
#extension GL_ARB_gpu_shader_int64 : require
layout(location = 0) out vec3 FragColor;
layout(location = 0) flat in double vTmp;
void main()
{
FragColor = vec3(dvec3(uint64BitsToDouble(0x7ff0000000000000ul), uint64BitsToDouble(0xfff0000000000000ul), uint64BitsToDouble(0xfff8000000000000ul)) + dvec3(vTmp));
}

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

@ -0,0 +1,11 @@
#version 310 es
precision mediump float;
precision highp int;
layout(location = 0) out highp vec3 FragColor;
void main()
{
FragColor = vec3(uintBitsToFloat(0x7f800000u), uintBitsToFloat(0xff800000u), uintBitsToFloat(0xffc00000u));
}

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

@ -0,0 +1,14 @@
#version 310 es
precision highp float;
const float posinf = 1.0 / 0.0;
const float neginf = -1.0 / 0.0;
const float nan = 0.0 / 0.0;
layout(location = 0) out vec3 FragColor;
void main()
{
FragColor = vec3(posinf, neginf, nan);
}

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

@ -0,0 +1,14 @@
#version 310 es
precision highp float;
const float posinf = 1.0 / 0.0;
const float neginf = -1.0 / 0.0;
const float nan = 0.0 / 0.0;
layout(location = 0) out vec3 FragColor;
void main()
{
FragColor = vec3(posinf, neginf, nan);
}

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

@ -0,0 +1,13 @@
#version 450
const double posinf = 1.0lf / 0.0lf;
const double neginf = -1.0lf / 0.0lf;
const double nan = 0.0lf / 0.0lf;
layout(location = 0) out vec3 FragColor;
layout(location = 0) flat in double vTmp;
void main()
{
FragColor = vec3(dvec3(posinf, neginf, nan) + vTmp);
}

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

@ -0,0 +1,14 @@
#version 310 es
precision highp float;
const float posinf = 1.0 / 0.0;
const float neginf = -1.0 / 0.0;
const float nan = 0.0 / 0.0;
layout(location = 0) out vec3 FragColor;
void main()
{
FragColor = vec3(posinf, neginf, nan);
}

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

@ -125,6 +125,8 @@ inline std::string convert_to_string(T &&t)
#endif
#ifdef _MSC_VER
// sprintf warning.
// We cannot rely on snprintf existing because, ..., MSVC.
#pragma warning(push)
#pragma warning(disable : 4996)
#endif

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

@ -19,6 +19,7 @@
#include "spirv_common.hpp"
#include <algorithm>
#include <assert.h>
#include <cmath>
#include <utility>
using namespace spv;
@ -371,6 +372,7 @@ string CompilerGLSL::compile()
if (options.vulkan_semantics)
backend.allow_precision_qualifiers = true;
backend.force_gl_in_out_block = true;
backend.supports_extensions = true;
// Scan the SPIR-V to find trivial uses of extensions.
find_static_extensions();
@ -2529,6 +2531,149 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c)
}
}
#ifdef _MSC_VER
// sprintf warning.
// We cannot rely on snprintf existing because, ..., MSVC.
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
{
string res;
float float_value = c.scalar_f32(col, row);
if (isnan(float_value) || isinf(float_value))
{
// Use special representation.
if (!is_legacy())
{
SPIRType out_type;
SPIRType in_type;
out_type.basetype = SPIRType::Float;
in_type.basetype = SPIRType::UInt;
out_type.vecsize = 1;
in_type.vecsize = 1;
out_type.width = 32;
in_type.width = 32;
char print_buffer[32];
sprintf(print_buffer, "0x%xu", c.scalar(col, row));
res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
}
else
{
if (float_value == numeric_limits<float>::infinity())
{
if (backend.float_literal_suffix)
res = "(1.0f / 0.0f)";
else
res = "(1.0 / 0.0)";
}
else if (float_value == -numeric_limits<float>::infinity())
{
if (backend.float_literal_suffix)
res = "(-1.0f / 0.0f)";
else
res = "(-1.0 / 0.0)";
}
else if (isnan(float_value))
{
if (backend.float_literal_suffix)
res = "(0.0f / 0.0f)";
else
res = "(0.0 / 0.0)";
}
else
SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
}
}
else
{
res = convert_to_string(float_value);
if (backend.float_literal_suffix)
res += "f";
}
return res;
}
std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32_t col, uint32_t row)
{
string res;
float double_value = c.scalar_f64(col, row);
if (isnan(double_value) || isinf(double_value))
{
// Use special representation.
if (!is_legacy())
{
SPIRType out_type;
SPIRType in_type;
out_type.basetype = SPIRType::Double;
in_type.basetype = SPIRType::UInt64;
out_type.vecsize = 1;
in_type.vecsize = 1;
out_type.width = 64;
in_type.width = 64;
uint64_t u64_value = c.scalar_u64(col, row);
if (options.es)
SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile.");
require_extension("GL_ARB_gpu_shader_int64");
char print_buffer[64];
sprintf(print_buffer, "0x%llx%s", static_cast<unsigned long long>(u64_value),
backend.long_long_literal_suffix ? "ull" : "ul");
res = join(bitcast_glsl_op(out_type, in_type), "(", print_buffer, ")");
}
else
{
if (options.es)
SPIRV_CROSS_THROW("FP64 not supported in ES profile.");
if (options.version < 400)
require_extension("GL_ARB_gpu_shader_fp64");
if (double_value == numeric_limits<double>::infinity())
{
if (backend.double_literal_suffix)
res = "(1.0lf / 0.0lf)";
else
res = "(1.0 / 0.0)";
}
else if (double_value == -numeric_limits<double>::infinity())
{
if (backend.double_literal_suffix)
res = "(-1.0lf / 0.0lf)";
else
res = "(-1.0 / 0.0)";
}
else if (isnan(double_value))
{
if (backend.double_literal_suffix)
res = "(0.0lf / 0.0lf)";
else
res = "(0.0 / 0.0)";
}
else
SPIRV_CROSS_THROW("Cannot represent non-finite floating point constant.");
}
}
else
{
res = convert_to_string(double_value);
if (backend.double_literal_suffix)
res += "lf";
}
return res;
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t vector)
{
auto type = get<SPIRType>(c.constant_type);
@ -2595,10 +2740,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
case SPIRType::Float:
if (splat || swizzle_splat)
{
res += convert_to_string(c.scalar_f32(vector, 0));
if (backend.float_literal_suffix)
res += "f";
res += convert_float_to_string(c, vector, 0);
if (swizzle_splat)
res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
}
@ -2609,10 +2751,8 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
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_to_string(c.scalar_f32(vector, i));
res += convert_float_to_string(c, vector, i);
if (backend.float_literal_suffix)
res += "f";
if (i + 1 < c.vector_size())
res += ", ";
}
@ -2622,10 +2762,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
case SPIRType::Double:
if (splat || swizzle_splat)
{
res += convert_to_string(c.scalar_f64(vector, 0));
if (backend.double_literal_suffix)
res += "lf";
res += convert_double_to_string(c, vector, 0);
if (swizzle_splat)
res = remap_swizzle(get<SPIRType>(c.constant_type), 1, res);
}
@ -2636,11 +2773,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
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_to_string(c.scalar_f64(vector, i));
if (backend.double_literal_suffix)
res += "lf";
}
res += convert_double_to_string(c, vector, i);
if (i + 1 < c.vector_size())
res += ", ";
@ -7672,7 +7805,7 @@ bool CompilerGLSL::has_extension(const std::string &ext) const
void CompilerGLSL::require_extension(const string &ext)
{
if (!has_extension(ext))
if (backend.supports_extensions && !has_extension(ext))
{
forced_extensions.push_back(ext);
force_recompile = true;

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

@ -333,6 +333,7 @@ protected:
bool force_gl_in_out_block = false;
bool can_return_array = true;
bool allow_truncated_access_chain = false;
bool supports_extensions = false;
} backend;
void emit_struct(SPIRType &type);
@ -525,6 +526,9 @@ protected:
const Instruction *get_next_instruction_in_block(const Instruction &instr);
static uint32_t mask_relevant_memory_semantics(uint32_t semantics);
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);
private:
void init()
{