diff --git a/reference/shaders/desktop-only/comp/fp64.comp b/reference/shaders/desktop-only/comp/fp64.comp new file mode 100644 index 00000000..1d5f0635 --- /dev/null +++ b/reference/shaders/desktop-only/comp/fp64.comp @@ -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); +} + diff --git a/shaders/desktop-only/comp/fp64.comp b/shaders/desktop-only/comp/fp64.comp new file mode 100644 index 00000000..0d225f53 --- /dev/null +++ b/shaders/desktop-only/comp/fp64.comp @@ -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); +} diff --git a/spirv_common.hpp b/spirv_common.hpp index 2deb5afd..c4aeabe9 100644 --- a/spirv_common.hpp +++ b/spirv_common.hpp @@ -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_) { diff --git a/spirv_cpp.cpp b/spirv_cpp.cpp index 84ddf978..bac5b42a 100644 --- a/spirv_cpp.cpp +++ b/spirv_cpp.cpp @@ -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"; diff --git a/spirv_cross.cpp b/spirv_cross.cpp index 5b77c851..d1668ea3 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -1030,7 +1030,7 @@ void Compiler::parse(const Instruction &instruction) uint32_t id = ops[0]; uint32_t width = ops[1]; auto &type = set(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(id, ops[0], ops[2]).specialization = op == OpSpecConstant; + auto &type = get(ops[0]); + if (type.basetype == SPIRType::Double) + set(id, ops[0], ops[2] | (uint64_t(ops[3]) << 32)).specialization = op == OpSpecConstant; + else + set(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(id, ops[0], 0).specialization = op == OpSpecConstantFalse; + set(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(id, ops[0], 1).specialization = op == OpSpecConstantTrue; + set(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(id, type, get(ops[2]).scalar()); + if (type_64bit) + constant = &set(id, type, get(ops[2]).scalar_u64()); + else + constant = &set(id, type, get(ops[2]).scalar()); break; case 2: - constant = &set(id, type, get(ops[2]).scalar(), - get(ops[3]).scalar()); + if (type_64bit) + { + constant = &set(id, type, get(ops[2]).scalar_u64(), + get(ops[3]).scalar_u64()); + } + else + { + constant = &set(id, type, get(ops[2]).scalar(), + get(ops[3]).scalar()); + } break; case 3: - constant = &set(id, type, get(ops[2]).scalar(), - get(ops[3]).scalar(), get(ops[4]).scalar()); + if (type_64bit) + { + constant = &set(id, type, get(ops[2]).scalar_u64(), + get(ops[3]).scalar_u64(), + get(ops[4]).scalar_u64()); + } + else + { + constant = + &set(id, type, get(ops[2]).scalar(), + get(ops[3]).scalar(), get(ops[4]).scalar()); + } break; case 4: - constant = - &set(id, type, get(ops[2]).scalar(), get(ops[3]).scalar(), - get(ops[4]).scalar(), get(ops[5]).scalar()); + if (type_64bit) + { + constant = &set( + id, type, get(ops[2]).scalar_u64(), get(ops[3]).scalar_u64(), + get(ops[4]).scalar_u64(), get(ops[5]).scalar_u64()); + } + else + { + constant = &set( + id, type, get(ops[2]).scalar(), get(ops[3]).scalar(), + get(ops[4]).scalar(), get(ops[5]).scalar()); + } break; default: diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp index 21677c82..9e149cf2 100644 --- a/spirv_glsl.cpp +++ b/spirv_glsl.cpp @@ -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(); + 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 "???"; } diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp index e0045cf2..be531c3b 100644 --- a/spirv_glsl.hpp +++ b/spirv_glsl.hpp @@ -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 &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(); }; }