Add support for FP64 in GLSL.

This commit is contained in:
Hans-Kristian Arntzen 2016-07-27 10:59:00 +02:00
parent 81d00da573
commit fa0255c43b
7 changed files with 371 additions and 26 deletions

View File

@ -0,0 +1,81 @@
#version 450
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
struct M0
{
double v;
dvec2 b[2];
dmat2x3 c;
dmat3x2 d;
};
layout(binding = 0, std430) buffer SSBO0
{
dvec4 a;
M0 m0;
dmat4 b;
} ssbo_0;
layout(binding = 1, std430) buffer SSBO1
{
dmat4 a;
dvec4 b;
M0 m0;
} ssbo_1;
layout(binding = 2, std430) buffer SSBO2
{
double a[4];
dvec2 b[4];
} ssbo_2;
layout(binding = 3, std140) buffer SSBO3
{
double a[4];
dvec2 b[4];
} ssbo_3;
void main()
{
ssbo_0.a = (ssbo_0.a + dvec4(10.0lf, 20.0lf, 30.0lf, 40.0lf));
ssbo_0.a = (ssbo_0.a + dvec4(20.0lf));
dvec4 a = ssbo_0.a;
dmat4 amat = ssbo_0.b;
ssbo_0.a = abs(a);
ssbo_0.a = sign(a);
ssbo_0.a = floor(a);
ssbo_0.a = trunc(a);
ssbo_0.a = round(a);
ssbo_0.a = roundEven(a);
ssbo_0.a = ceil(a);
ssbo_0.a = fract(a);
ssbo_0.a = mod(a, dvec4(20.0lf));
ssbo_0.a = mod(a, a);
ssbo_0.a = min(a, a);
ssbo_0.a = max(a, a);
ssbo_0.a = clamp(a, a, a);
ssbo_0.a = mix(a, a, a);
ssbo_0.a = step(a, a);
ssbo_0.a = smoothstep(a, a, a);
bvec4 b = isnan(a);
bvec4 c = isinf(a);
double f = packDouble2x32(uvec2(10u, 40u));
uvec2 g = unpackDouble2x32(f);
double d = length(a);
d = distance(a, a);
d = dot(a, a);
dvec3 e = cross(a.xyz, a.yzw);
a = faceforward(a, a, a);
a = reflect(a, a);
a = refract(a, a, a.x);
dmat4 l = dmat4((amat[0] * amat[0]), (amat[1] * amat[1]), (amat[2] * amat[2]), (amat[3] * amat[3]));
l = outerProduct(a, a);
l = transpose(l);
double m = determinant(l);
l = inverse(l);
bvec4 k = lessThan(a, a);
k = lessThanEqual(a, a);
k = greaterThan(a, a);
k = greaterThanEqual(a, a);
}

View File

@ -0,0 +1,87 @@
#version 450
layout(local_size_x = 1) in;
struct M0
{
double v;
dvec2 b[2];
dmat2x3 c;
dmat3x2 d;
};
// Test buffer layout handling.
layout(std430, binding = 0) buffer SSBO0
{
dvec4 a;
M0 m0;
dmat4 b;
} ssbo_0;
layout(std430, binding = 1) buffer SSBO1
{
dmat4 a;
dvec4 b;
M0 m0;
} ssbo_1;
layout(std430, binding = 2) buffer SSBO2
{
double a[4];
dvec2 b[4];
} ssbo_2;
layout(std140, binding = 3) buffer SSBO3
{
double a[4];
dvec2 b[4];
} ssbo_3;
void main()
{
ssbo_0.a += dvec4(10, 20, 30, 40);
ssbo_0.a += 20;
dvec4 a = ssbo_0.a;
dmat4 amat = ssbo_0.b;
ssbo_0.a = abs(a);
ssbo_0.a = sign(a);
ssbo_0.a = floor(a);
ssbo_0.a = trunc(a);
ssbo_0.a = round(a);
ssbo_0.a = roundEven(a);
ssbo_0.a = ceil(a);
ssbo_0.a = fract(a);
ssbo_0.a = mod(a, 20.0);
ssbo_0.a = mod(a, a);
ssbo_0.a = min(a, a);
ssbo_0.a = max(a, a);
ssbo_0.a = clamp(a, a, a);
ssbo_0.a = mix(a, a, a);
ssbo_0.a = step(a, a);
ssbo_0.a = smoothstep(a, a, a);
bvec4 b = isnan(a);
bvec4 c = isinf(a);
double f = packDouble2x32(uvec2(10, 40));
uvec2 g = unpackDouble2x32(f);
double d = length(a);
d = distance(a, a);
d = dot(a, a);
dvec3 e = cross(a.xyz, a.yzw);
a = faceforward(a, a, a);
a = reflect(a, a);
a = refract(a, a, a.x);
dmat4 l = matrixCompMult(amat, amat);
l = outerProduct(a, a);
l = transpose(l);
double m = determinant(l);
l = inverse(l);
bvec4 k = lessThan(a, a);
k = lessThanEqual(a, a);
k = greaterThan(a, a);
k = greaterThanEqual(a, a);
}

View File

@ -166,6 +166,7 @@ struct SPIRType : IVariant
UInt,
AtomicCounter,
Float,
Double,
Struct,
Image,
SampledImage,
@ -485,6 +486,10 @@ struct SPIRConstant : IVariant
uint32_t u32;
int32_t i32;
float f32;
uint64_t u64;
int64_t i64;
double f64;
};
struct ConstantVector
@ -509,11 +514,26 @@ struct SPIRConstant : IVariant
return m.c[col].r[row].f32;
}
inline int scalar_i32(uint32_t col = 0, uint32_t row = 0) const
inline int32_t scalar_i32(uint32_t col = 0, uint32_t row = 0) const
{
return m.c[col].r[row].i32;
}
inline double scalar_f64(uint32_t col = 0, uint32_t row = 0) const
{
return m.c[col].r[row].f64;
}
inline int64_t scalar_i64(uint32_t col = 0, uint32_t row = 0) const
{
return m.c[col].r[row].i64;
}
inline uint64_t scalar_u64(uint32_t col = 0, uint32_t row = 0) const
{
return m.c[col].r[row].u64;
}
inline const ConstantVector &vector() const
{
return m.c[0];
@ -571,6 +591,44 @@ struct SPIRConstant : IVariant
m.columns = 1;
}
SPIRConstant(uint32_t constant_type_, uint64_t v0)
: constant_type(constant_type_)
{
m.c[0].r[0].u64 = v0;
m.c[0].vecsize = 1;
m.columns = 1;
}
SPIRConstant(uint32_t constant_type_, uint64_t v0, uint64_t v1)
: constant_type(constant_type_)
{
m.c[0].r[0].u64 = v0;
m.c[0].r[1].u64 = v1;
m.c[0].vecsize = 2;
m.columns = 1;
}
SPIRConstant(uint32_t constant_type_, uint64_t v0, uint64_t v1, uint64_t v2)
: constant_type(constant_type_)
{
m.c[0].r[0].u64 = v0;
m.c[0].r[1].u64 = v1;
m.c[0].r[2].u64 = v2;
m.c[0].vecsize = 3;
m.columns = 1;
}
SPIRConstant(uint32_t constant_type_, uint64_t v0, uint64_t v1, uint64_t v2, uint64_t v3)
: constant_type(constant_type_)
{
m.c[0].r[0].u64 = v0;
m.c[0].r[1].u64 = v1;
m.c[0].r[2].u64 = v2;
m.c[0].r[3].u64 = v3;
m.c[0].vecsize = 4;
m.columns = 1;
}
SPIRConstant(uint32_t constant_type_, const ConstantVector &vec0)
: constant_type(constant_type_)
{

View File

@ -273,6 +273,7 @@ string CompilerCPP::compile()
options.es = false;
options.version = 450;
backend.float_literal_suffix = true;
backend.double_literal_suffix = false;
backend.uint32_t_literal_suffix = true;
backend.basic_int_type = "int32_t";
backend.basic_uint_type = "uint32_t";

View File

@ -1030,7 +1030,7 @@ void Compiler::parse(const Instruction &instruction)
uint32_t id = ops[0];
uint32_t width = ops[1];
auto &type = set<SPIRType>(id);
type.basetype = SPIRType::Float;
type.basetype = width > 32 ? SPIRType::Double : SPIRType::Float;
type.width = width;
break;
}
@ -1267,7 +1267,11 @@ void Compiler::parse(const Instruction &instruction)
case OpConstant:
{
uint32_t id = ops[1];
set<SPIRConstant>(id, ops[0], ops[2]).specialization = op == OpSpecConstant;
auto &type = get<SPIRType>(ops[0]);
if (type.basetype == SPIRType::Double)
set<SPIRConstant>(id, ops[0], ops[2] | (uint64_t(ops[3]) << 32)).specialization = op == OpSpecConstant;
else
set<SPIRConstant>(id, ops[0], ops[2]).specialization = op == OpSpecConstant;
break;
}
@ -1275,7 +1279,7 @@ void Compiler::parse(const Instruction &instruction)
case OpConstantFalse:
{
uint32_t id = ops[1];
set<SPIRConstant>(id, ops[0], 0).specialization = op == OpSpecConstantFalse;
set<SPIRConstant>(id, ops[0], uint32_t(0)).specialization = op == OpSpecConstantFalse;
break;
}
@ -1283,7 +1287,7 @@ void Compiler::parse(const Instruction &instruction)
case OpConstantTrue:
{
uint32_t id = ops[1];
set<SPIRConstant>(id, ops[0], 1).specialization = op == OpSpecConstantTrue;
set<SPIRConstant>(id, ops[0], uint32_t(1)).specialization = op == OpSpecConstantTrue;
break;
}
@ -1306,6 +1310,7 @@ void Compiler::parse(const Instruction &instruction)
break;
}
bool type_64bit = ctype.width > 32;
bool matrix = ctype.columns > 1;
if (matrix)
@ -1341,23 +1346,53 @@ void Compiler::parse(const Instruction &instruction)
switch (length - 2)
{
case 1:
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar());
if (type_64bit)
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar_u64());
else
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar());
break;
case 2:
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar(),
get<SPIRConstant>(ops[3]).scalar());
if (type_64bit)
{
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar_u64(),
get<SPIRConstant>(ops[3]).scalar_u64());
}
else
{
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar(),
get<SPIRConstant>(ops[3]).scalar());
}
break;
case 3:
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar(),
get<SPIRConstant>(ops[3]).scalar(), get<SPIRConstant>(ops[4]).scalar());
if (type_64bit)
{
constant = &set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar_u64(),
get<SPIRConstant>(ops[3]).scalar_u64(),
get<SPIRConstant>(ops[4]).scalar_u64());
}
else
{
constant =
&set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar(),
get<SPIRConstant>(ops[3]).scalar(), get<SPIRConstant>(ops[4]).scalar());
}
break;
case 4:
constant =
&set<SPIRConstant>(id, type, get<SPIRConstant>(ops[2]).scalar(), get<SPIRConstant>(ops[3]).scalar(),
get<SPIRConstant>(ops[4]).scalar(), get<SPIRConstant>(ops[5]).scalar());
if (type_64bit)
{
constant = &set<SPIRConstant>(
id, type, get<SPIRConstant>(ops[2]).scalar_u64(), get<SPIRConstant>(ops[3]).scalar_u64(),
get<SPIRConstant>(ops[4]).scalar_u64(), get<SPIRConstant>(ops[5]).scalar_u64());
}
else
{
constant = &set<SPIRConstant>(
id, type, get<SPIRConstant>(ops[2]).scalar(), get<SPIRConstant>(ops[3]).scalar(),
get<SPIRConstant>(ops[4]).scalar(), get<SPIRConstant>(ops[5]).scalar());
}
break;
default:

View File

@ -176,8 +176,29 @@ void CompilerGLSL::remap_pls_variables()
}
}
void CompilerGLSL::find_static_extensions()
{
for (auto &id : ids)
{
if (id.get_type() == TypeType)
{
auto &type = id.get<SPIRType>();
if (type.basetype == SPIRType::Double)
{
if (options.es)
throw CompilerError("FP64 not supported in ES profile.");
if (!options.es && options.version < 400)
require_extension("GL_ARB_gpu_shader_fp64");
}
}
}
}
string CompilerGLSL::compile()
{
// Scan the SPIR-V to find trivial uses of extensions.
find_static_extensions();
uint32_t pass_count = 0;
do
{
@ -578,10 +599,20 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format)
}
}
uint32_t CompilerGLSL::type_to_std430_base_size(const SPIRType &type)
{
switch (type.basetype)
{
case SPIRType::Double:
return 8;
default:
return 4;
}
}
uint32_t CompilerGLSL::type_to_std430_alignment(const SPIRType &type, uint64_t flags)
{
// float, int and uint all take 4 bytes.
const uint32_t base_alignment = 4;
const uint32_t base_alignment = type_to_std430_base_size(type);
if (type.basetype == SPIRType::Struct)
{
@ -654,8 +685,7 @@ uint32_t CompilerGLSL::type_to_std430_size(const SPIRType &type, uint64_t flags)
if (!type.array.empty())
return type.array.back() * type_to_std430_array_stride(type, flags);
// float, int and uint all take 4 bytes.
const uint32_t base_alignment = 4;
const uint32_t base_alignment = type_to_std430_base_size(type);
uint32_t size = 0;
if (type.basetype == SPIRType::Struct)
@ -1309,10 +1339,20 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
bool splat = c.vector_size() > 1;
if (splat)
{
uint32_t ident = c.scalar(vector, 0);
for (uint32_t i = 1; i < c.vector_size(); i++)
if (ident != c.scalar(vector, i))
splat = false;
if (type_to_std430_base_size(type) == 8)
{
uint64_t ident = c.scalar_u64(vector, 0);
for (uint32_t i = 1; i < c.vector_size(); i++)
if (ident != c.scalar_u64(vector, i))
splat = false;
}
else
{
uint32_t ident = c.scalar(vector, 0);
for (uint32_t i = 1; i < c.vector_size(); i++)
if (ident != c.scalar(vector, i))
splat = false;
}
}
switch (type.basetype)
@ -1337,6 +1377,26 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
}
break;
case SPIRType::Double:
if (splat)
{
res += convert_to_string(c.scalar_f64(vector, 0));
if (backend.double_literal_suffix)
res += "lf";
}
else
{
for (uint32_t i = 0; i < c.vector_size(); i++)
{
res += convert_to_string(c.scalar_f64(vector, i));
if (backend.double_literal_suffix)
res += "lf";
if (i + 1 < c.vector_size())
res += ", ";
}
}
break;
case SPIRType::UInt:
if (splat)
{
@ -1980,9 +2040,16 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
{
// FP fiddling
case GLSLstd450Round:
case GLSLstd450RoundEven:
emit_unary_func_op(result_type, id, args[0], "round");
break;
case GLSLstd450RoundEven:
if ((options.es && options.version >= 300) || (!options.es && options.version >= 130))
emit_unary_func_op(result_type, id, args[0], "roundEven");
else
throw CompilerError("roundEven supported only in ESSL 300 and GLSL 130 and up.");
break;
case GLSLstd450Trunc:
emit_unary_func_op(result_type, id, args[0], "trunc");
break;
@ -2161,6 +2228,13 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
emit_unary_func_op(result_type, id, args[0], "unpackHalf2x16");
break;
case GLSLstd450PackDouble2x32:
emit_unary_func_op(result_type, id, args[0], "packDouble2x32");
break;
case GLSLstd450UnpackDouble2x32:
emit_unary_func_op(result_type, id, args[0], "unpackDouble2x32");
break;
// Vector math
case GLSLstd450Length:
emit_unary_func_op(result_type, id, args[0], "length");
@ -3129,7 +3203,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
break;
case OpOuterProduct:
UFOP(outerProduct);
BFOP(outerProduct);
break;
case OpDot:
@ -3957,7 +4031,7 @@ const char *CompilerGLSL::flags_to_precision_qualifiers_glsl(const SPIRType &typ
{
if (options.es)
{
// Structs do not have precision qualifiers.
// Structs do not have precision qualifiers, neither do doubles (desktop only anyways, so no mediump/highp).
if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt &&
type.basetype != SPIRType::Image && type.basetype != SPIRType::SampledImage &&
type.basetype != SPIRType::Sampler)
@ -4232,6 +4306,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
return "atomic_uint";
case SPIRType::Float:
return "float";
case SPIRType::Double:
return "double";
default:
return "???";
}
@ -4248,6 +4324,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
return join("uvec", type.vecsize);
case SPIRType::Float:
return join("vec", type.vecsize);
case SPIRType::Double:
return join("dvec", type.vecsize);
default:
return "???";
}
@ -4264,6 +4342,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
return join("umat", type.vecsize);
case SPIRType::Float:
return join("mat", type.vecsize);
case SPIRType::Double:
return join("dmat", type.vecsize);
default:
return "???";
}
@ -4280,6 +4360,8 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type)
return join("umat", type.columns, "x", type.vecsize);
case SPIRType::Float:
return join("mat", type.columns, "x", type.vecsize);
case SPIRType::Double:
return join("dmat", type.columns, "x", type.vecsize);
default:
return "???";
}

View File

@ -218,6 +218,7 @@ protected:
struct BackendVariations
{
bool float_literal_suffix = false;
bool double_literal_suffix = true;
bool uint32_t_literal_suffix = true;
const char *basic_int_type = "int";
const char *basic_uint_type = "uint";
@ -291,6 +292,7 @@ protected:
std::string layout_for_variable(const SPIRVariable &variable);
bool ssbo_is_std430_packing(const SPIRType &type);
uint32_t type_to_std430_base_size(const SPIRType &type);
uint32_t type_to_std430_alignment(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_array_stride(const SPIRType &type, uint64_t flags);
uint32_t type_to_std430_size(const SPIRType &type, uint64_t flags);
@ -343,10 +345,9 @@ protected:
void remap_pls_variables();
void add_variable(std::unordered_set<std::string> &variables, uint32_t id);
void check_function_call_constraints(const uint32_t *args, uint32_t length);
void handle_invalid_expression(uint32_t id);
void find_static_extensions();
};
}