Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Cross.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Kristian Arntzen <post@arntzen-software.no>2019-01-30 16:49:55 +0300
committerHans-Kristian Arntzen <post@arntzen-software.no>2019-01-30 17:45:24 +0300
commit2ed171e525992ff997c20d8384f2993a6106d723 (patch)
tree10ec3e71906ec1e324209dc0008792e6d6809760
parent2edee351f0fe3b62ecea754d22327041c9db2603 (diff)
GLSL/MSL: Implement 8-bit part of VK_KHR_shader_float16_int8.
Storage was in place already, so mostly just dealing with bitcasts and constants. Simplies some of the bitcasting logic, and this exposed some bugs in the implementation. Refactor to use correct width integers with explicit bitcast opcodes.
-rw-r--r--reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag77
-rw-r--r--reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp4
-rw-r--r--reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp4
-rw-r--r--reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag2
-rw-r--r--reference/opt/shaders/frag/16bit-constants.frag4
-rw-r--r--reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk69
-rw-r--r--reference/opt/shaders/vulkan/vert/small-storage.vk.vert6
-rw-r--r--reference/opt/shaders/vulkan/vert/small-storage.vk.vert.vk12
-rw-r--r--reference/shaders-msl/frag/shader-arithmetic-8bit.frag98
-rw-r--r--reference/shaders/comp/bitcast-16bit-1.invalid.comp4
-rw-r--r--reference/shaders/comp/bitcast-16bit-2.invalid.comp4
-rw-r--r--reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag2
-rw-r--r--reference/shaders/frag/16bit-constants.frag4
-rw-r--r--reference/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk88
-rw-r--r--reference/shaders/vulkan/vert/small-storage.vk.vert6
-rw-r--r--reference/shaders/vulkan/vert/small-storage.vk.vert.vk12
-rw-r--r--shaders-msl/frag/shader-arithmetic-8bit.frag88
-rw-r--r--shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag88
-rw-r--r--spirv_common.hpp65
-rw-r--r--spirv_glsl.cpp262
-rw-r--r--spirv_glsl.hpp2
-rw-r--r--spirv_hlsl.cpp33
-rw-r--r--spirv_msl.cpp82
-rw-r--r--spirv_parser.cpp18
24 files changed, 835 insertions, 199 deletions
diff --git a/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag b/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag
new file mode 100644
index 00000000..fcc7de31
--- /dev/null
+++ b/reference/opt/shaders-msl/frag/shader-arithmetic-8bit.frag
@@ -0,0 +1,77 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct SSBO
+{
+ char i8[16];
+ uchar u8[16];
+};
+
+struct Push
+{
+ char i8;
+ uchar u8;
+};
+
+struct UBO
+{
+ char i8;
+ uchar u8;
+};
+
+struct main0_out
+{
+ int4 FragColorInt [[color(0)]];
+ uint4 FragColorUint [[color(1)]];
+};
+
+struct main0_in
+{
+ int4 vColor [[user(locn0)]];
+};
+
+fragment main0_out main0(main0_in in [[stage_in]], constant Push& registers [[buffer(0)]], constant UBO& ubo [[buffer(0)]], device SSBO& ssbo [[buffer(1)]])
+{
+ main0_out out = {};
+ short _196 = 10;
+ int _197 = 20;
+ char2 _198 = as_type<char2>(_196);
+ char4 _199 = as_type<char4>(_197);
+ _196 = as_type<short>(_198);
+ _197 = as_type<int>(_199);
+ ssbo.i8[0] = _199.x;
+ ssbo.i8[1] = _199.y;
+ ssbo.i8[2] = _199.z;
+ ssbo.i8[3] = _199.w;
+ ushort _220 = 10u;
+ uint _221 = 20u;
+ uchar2 _222 = as_type<uchar2>(_220);
+ uchar4 _223 = as_type<uchar4>(_221);
+ _220 = as_type<ushort>(_222);
+ _221 = as_type<uint>(_223);
+ ssbo.u8[0] = _223.x;
+ ssbo.u8[1] = _223.y;
+ ssbo.u8[2] = _223.z;
+ ssbo.u8[3] = _223.w;
+ char4 _246 = char4(in.vColor);
+ char4 _244 = _246;
+ _244 += char4(registers.i8);
+ _244 += char4(-40);
+ _244 += char4(-50);
+ _244 += char4(char(10), char(20), char(30), char(40));
+ _244 += char4(ssbo.i8[4]);
+ _244 += char4(ubo.i8);
+ out.FragColorInt = int4(_244);
+ uchar4 _271 = uchar4(_246);
+ _271 += uchar4(registers.u8);
+ _271 += uchar4(216);
+ _271 += uchar4(206);
+ _271 += uchar4(uchar(10), uchar(20), uchar(30), uchar(40));
+ _271 += uchar4(ssbo.u8[4]);
+ _271 += uchar4(ubo.u8);
+ out.FragColorUint = uint4(_271);
+ return out;
+}
+
diff --git a/reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp b/reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp
index 9844e719..a4014e89 100644
--- a/reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp
+++ b/reference/opt/shaders/comp/bitcast-16bit-1.invalid.comp
@@ -3,15 +3,11 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
diff --git a/reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp b/reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp
index 416bc4a2..bddc16d6 100644
--- a/reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp
+++ b/reference/opt/shaders/comp/bitcast-16bit-2.invalid.comp
@@ -1,8 +1,6 @@
#version 450
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
@@ -10,8 +8,6 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag b/reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag
index af8882c4..e1fc045c 100644
--- a/reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag
+++ b/reference/opt/shaders/desktop-only/frag/fp16.invalid.desktop.frag
@@ -3,8 +3,6 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/opt/shaders/frag/16bit-constants.frag b/reference/opt/shaders/frag/16bit-constants.frag
index 48fbad97..f9ce356f 100644
--- a/reference/opt/shaders/frag/16bit-constants.frag
+++ b/reference/opt/shaders/frag/16bit-constants.frag
@@ -3,15 +3,11 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
diff --git a/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk b/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk
new file mode 100644
index 00000000..d09930f3
--- /dev/null
+++ b/reference/opt/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk
@@ -0,0 +1,69 @@
+#version 450
+#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
+#extension GL_EXT_shader_16bit_storage : require
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
+#extension GL_EXT_shader_8bit_storage : require
+
+layout(set = 0, binding = 1, std430) buffer SSBO
+{
+ int8_t i8[16];
+ uint8_t u8[16];
+} ssbo;
+
+layout(set = 0, binding = 0, std140) uniform UBO
+{
+ int8_t i8;
+ uint8_t u8;
+} ubo;
+
+layout(push_constant, std430) uniform Push
+{
+ int8_t i8;
+ uint8_t u8;
+} registers;
+
+layout(location = 0) flat in ivec4 vColor;
+layout(location = 0) out ivec4 FragColorInt;
+layout(location = 1) out uvec4 FragColorUint;
+
+void main()
+{
+ int16_t _196 = 10s;
+ int _197 = 20;
+ i8vec2 _198 = unpack8(_196);
+ i8vec4 _199 = unpack8(_197);
+ _196 = pack16(_198);
+ _197 = pack32(_199);
+ ssbo.i8[0] = _199.x;
+ ssbo.i8[1] = _199.y;
+ ssbo.i8[2] = _199.z;
+ ssbo.i8[3] = _199.w;
+ uint16_t _220 = 10us;
+ uint _221 = 20u;
+ u8vec2 _222 = unpack8(_220);
+ u8vec4 _223 = unpack8(_221);
+ _220 = pack16(_222);
+ _221 = pack32(_223);
+ ssbo.u8[0] = _223.x;
+ ssbo.u8[1] = _223.y;
+ ssbo.u8[2] = _223.z;
+ ssbo.u8[3] = _223.w;
+ i8vec4 _246 = i8vec4(vColor);
+ i8vec4 _244 = _246;
+ _244 += i8vec4(registers.i8);
+ _244 += i8vec4(-40);
+ _244 += i8vec4(-50);
+ _244 += i8vec4(int8_t(10), int8_t(20), int8_t(30), int8_t(40));
+ _244 += i8vec4(ssbo.i8[4]);
+ _244 += i8vec4(ubo.i8);
+ FragColorInt = ivec4(_244);
+ u8vec4 _271 = u8vec4(_246);
+ _271 += u8vec4(registers.u8);
+ _271 += u8vec4(216);
+ _271 += u8vec4(206);
+ _271 += u8vec4(uint8_t(10), uint8_t(20), uint8_t(30), uint8_t(40));
+ _271 += u8vec4(ssbo.u8[4]);
+ _271 += u8vec4(ubo.u8);
+ FragColorUint = uvec4(_271);
+}
+
diff --git a/reference/opt/shaders/vulkan/vert/small-storage.vk.vert b/reference/opt/shaders/vulkan/vert/small-storage.vk.vert
index 2ade8110..b3aafc8d 100644
--- a/reference/opt/shaders/vulkan/vert/small-storage.vk.vert
+++ b/reference/opt/shaders/vulkan/vert/small-storage.vk.vert
@@ -1,18 +1,14 @@
#version 450
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
-#extension GL_EXT_shader_8bit_storage : require
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
#if defined(GL_AMD_gpu_shader_half_float)
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/opt/shaders/vulkan/vert/small-storage.vk.vert.vk b/reference/opt/shaders/vulkan/vert/small-storage.vk.vert.vk
index c283d606..caec60a2 100644
--- a/reference/opt/shaders/vulkan/vert/small-storage.vk.vert.vk
+++ b/reference/opt/shaders/vulkan/vert/small-storage.vk.vert.vk
@@ -1,16 +1,12 @@
#version 450
-#if defined(GL_AMD_gpu_shader_int16)
-#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
+#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
#extension GL_EXT_shader_16bit_storage : require
-#else
-#error No extension available for Int16.
-#endif
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
#extension GL_EXT_shader_8bit_storage : require
#if defined(GL_AMD_gpu_shader_half_float)
#extension GL_AMD_gpu_shader_half_float : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
+#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)
+#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/shaders-msl/frag/shader-arithmetic-8bit.frag b/reference/shaders-msl/frag/shader-arithmetic-8bit.frag
new file mode 100644
index 00000000..d7f1c3b6
--- /dev/null
+++ b/reference/shaders-msl/frag/shader-arithmetic-8bit.frag
@@ -0,0 +1,98 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct SSBO
+{
+ char i8[16];
+ uchar u8[16];
+};
+
+struct Push
+{
+ char i8;
+ uchar u8;
+};
+
+struct UBO
+{
+ char i8;
+ uchar u8;
+};
+
+struct main0_out
+{
+ int4 FragColorInt [[color(0)]];
+ uint4 FragColorUint [[color(1)]];
+};
+
+struct main0_in
+{
+ int4 vColor [[user(locn0)]];
+};
+
+void packing_int8(device SSBO& ssbo)
+{
+ short i16 = 10;
+ int i32 = 20;
+ char2 i8_2 = as_type<char2>(i16);
+ char4 i8_4 = as_type<char4>(i32);
+ i16 = as_type<short>(i8_2);
+ i32 = as_type<int>(i8_4);
+ ssbo.i8[0] = i8_4.x;
+ ssbo.i8[1] = i8_4.y;
+ ssbo.i8[2] = i8_4.z;
+ ssbo.i8[3] = i8_4.w;
+}
+
+void packing_uint8(device SSBO& ssbo)
+{
+ ushort u16 = 10u;
+ uint u32 = 20u;
+ uchar2 u8_2 = as_type<uchar2>(u16);
+ uchar4 u8_4 = as_type<uchar4>(u32);
+ u16 = as_type<ushort>(u8_2);
+ u32 = as_type<uint>(u8_4);
+ ssbo.u8[0] = u8_4.x;
+ ssbo.u8[1] = u8_4.y;
+ ssbo.u8[2] = u8_4.z;
+ ssbo.u8[3] = u8_4.w;
+}
+
+void compute_int8(device SSBO& ssbo, thread int4& vColor, constant Push& registers, constant UBO& ubo, thread int4& FragColorInt)
+{
+ char4 tmp = char4(vColor);
+ tmp += char4(registers.i8);
+ tmp += char4(char(-40));
+ tmp += char4(-50);
+ tmp += char4(char(10), char(20), char(30), char(40));
+ tmp += char4(ssbo.i8[4]);
+ tmp += char4(ubo.i8);
+ FragColorInt = int4(tmp);
+}
+
+void compute_uint8(device SSBO& ssbo, thread int4& vColor, constant Push& registers, constant UBO& ubo, thread uint4& FragColorUint)
+{
+ uchar4 tmp = uchar4(char4(vColor));
+ tmp += uchar4(registers.u8);
+ tmp += uchar4(uchar(216));
+ tmp += uchar4(206);
+ tmp += uchar4(uchar(10), uchar(20), uchar(30), uchar(40));
+ tmp += uchar4(ssbo.u8[4]);
+ tmp += uchar4(ubo.u8);
+ FragColorUint = uint4(tmp);
+}
+
+fragment main0_out main0(main0_in in [[stage_in]], constant Push& registers [[buffer(0)]], constant UBO& ubo [[buffer(0)]], device SSBO& ssbo [[buffer(1)]])
+{
+ main0_out out = {};
+ packing_int8(ssbo);
+ packing_uint8(ssbo);
+ compute_int8(ssbo, in.vColor, registers, ubo, out.FragColorInt);
+ compute_uint8(ssbo, in.vColor, registers, ubo, out.FragColorUint);
+ return out;
+}
+
diff --git a/reference/shaders/comp/bitcast-16bit-1.invalid.comp b/reference/shaders/comp/bitcast-16bit-1.invalid.comp
index 9844e719..a4014e89 100644
--- a/reference/shaders/comp/bitcast-16bit-1.invalid.comp
+++ b/reference/shaders/comp/bitcast-16bit-1.invalid.comp
@@ -3,15 +3,11 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
diff --git a/reference/shaders/comp/bitcast-16bit-2.invalid.comp b/reference/shaders/comp/bitcast-16bit-2.invalid.comp
index 416bc4a2..bddc16d6 100644
--- a/reference/shaders/comp/bitcast-16bit-2.invalid.comp
+++ b/reference/shaders/comp/bitcast-16bit-2.invalid.comp
@@ -1,8 +1,6 @@
#version 450
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
@@ -10,8 +8,6 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag b/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag
index af8882c4..e1fc045c 100644
--- a/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag
+++ b/reference/shaders/desktop-only/frag/fp16.invalid.desktop.frag
@@ -3,8 +3,6 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/shaders/frag/16bit-constants.frag b/reference/shaders/frag/16bit-constants.frag
index 48fbad97..f9ce356f 100644
--- a/reference/shaders/frag/16bit-constants.frag
+++ b/reference/shaders/frag/16bit-constants.frag
@@ -3,15 +3,11 @@
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
diff --git a/reference/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk b/reference/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk
new file mode 100644
index 00000000..634a37aa
--- /dev/null
+++ b/reference/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag.vk
@@ -0,0 +1,88 @@
+#version 450
+#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
+#extension GL_EXT_shader_16bit_storage : require
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
+#extension GL_EXT_shader_8bit_storage : require
+
+layout(set = 0, binding = 1, std430) buffer SSBO
+{
+ int8_t i8[16];
+ uint8_t u8[16];
+} ssbo;
+
+layout(set = 0, binding = 0, std140) uniform UBO
+{
+ int8_t i8;
+ uint8_t u8;
+} ubo;
+
+layout(push_constant, std430) uniform Push
+{
+ int8_t i8;
+ uint8_t u8;
+} registers;
+
+layout(location = 0) flat in ivec4 vColor;
+layout(location = 0) out ivec4 FragColorInt;
+layout(location = 1) out uvec4 FragColorUint;
+
+void packing_int8()
+{
+ int16_t i16 = 10s;
+ int i32 = 20;
+ i8vec2 i8_2 = unpack8(i16);
+ i8vec4 i8_4 = unpack8(i32);
+ i16 = pack16(i8_2);
+ i32 = pack32(i8_4);
+ ssbo.i8[0] = i8_4.x;
+ ssbo.i8[1] = i8_4.y;
+ ssbo.i8[2] = i8_4.z;
+ ssbo.i8[3] = i8_4.w;
+}
+
+void packing_uint8()
+{
+ uint16_t u16 = 10us;
+ uint u32 = 20u;
+ u8vec2 u8_2 = unpack8(u16);
+ u8vec4 u8_4 = unpack8(u32);
+ u16 = pack16(u8_2);
+ u32 = pack32(u8_4);
+ ssbo.u8[0] = u8_4.x;
+ ssbo.u8[1] = u8_4.y;
+ ssbo.u8[2] = u8_4.z;
+ ssbo.u8[3] = u8_4.w;
+}
+
+void compute_int8()
+{
+ i8vec4 tmp = i8vec4(vColor);
+ tmp += i8vec4(registers.i8);
+ tmp += i8vec4(int8_t(-40));
+ tmp += i8vec4(-50);
+ tmp += i8vec4(int8_t(10), int8_t(20), int8_t(30), int8_t(40));
+ tmp += i8vec4(ssbo.i8[4]);
+ tmp += i8vec4(ubo.i8);
+ FragColorInt = ivec4(tmp);
+}
+
+void compute_uint8()
+{
+ u8vec4 tmp = u8vec4(i8vec4(vColor));
+ tmp += u8vec4(registers.u8);
+ tmp += u8vec4(uint8_t(216));
+ tmp += u8vec4(206);
+ tmp += u8vec4(uint8_t(10), uint8_t(20), uint8_t(30), uint8_t(40));
+ tmp += u8vec4(ssbo.u8[4]);
+ tmp += u8vec4(ubo.u8);
+ FragColorUint = uvec4(tmp);
+}
+
+void main()
+{
+ packing_int8();
+ packing_uint8();
+ compute_int8();
+ compute_uint8();
+}
+
diff --git a/reference/shaders/vulkan/vert/small-storage.vk.vert b/reference/shaders/vulkan/vert/small-storage.vk.vert
index 2ade8110..b3aafc8d 100644
--- a/reference/shaders/vulkan/vert/small-storage.vk.vert
+++ b/reference/shaders/vulkan/vert/small-storage.vk.vert
@@ -1,18 +1,14 @@
#version 450
#if defined(GL_AMD_gpu_shader_int16)
#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for Int16.
#endif
-#extension GL_EXT_shader_8bit_storage : require
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
#if defined(GL_AMD_gpu_shader_half_float)
#extension GL_AMD_gpu_shader_half_float : require
#elif defined(GL_NV_gpu_shader5)
#extension GL_NV_gpu_shader5 : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
#else
#error No extension available for FP16.
#endif
diff --git a/reference/shaders/vulkan/vert/small-storage.vk.vert.vk b/reference/shaders/vulkan/vert/small-storage.vk.vert.vk
index c283d606..caec60a2 100644
--- a/reference/shaders/vulkan/vert/small-storage.vk.vert.vk
+++ b/reference/shaders/vulkan/vert/small-storage.vk.vert.vk
@@ -1,16 +1,12 @@
#version 450
-#if defined(GL_AMD_gpu_shader_int16)
-#extension GL_AMD_gpu_shader_int16 : require
-#elif defined(GL_EXT_shader_16bit_storage)
+#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
#extension GL_EXT_shader_16bit_storage : require
-#else
-#error No extension available for Int16.
-#endif
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
#extension GL_EXT_shader_8bit_storage : require
#if defined(GL_AMD_gpu_shader_half_float)
#extension GL_AMD_gpu_shader_half_float : require
-#elif defined(GL_EXT_shader_16bit_storage)
-#extension GL_EXT_shader_16bit_storage : require
+#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)
+#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
#else
#error No extension available for FP16.
#endif
diff --git a/shaders-msl/frag/shader-arithmetic-8bit.frag b/shaders-msl/frag/shader-arithmetic-8bit.frag
new file mode 100644
index 00000000..d70b0dad
--- /dev/null
+++ b/shaders-msl/frag/shader-arithmetic-8bit.frag
@@ -0,0 +1,88 @@
+#version 450
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
+#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
+
+layout(location = 0) flat in ivec4 vColor;
+layout(location = 0) out ivec4 FragColorInt;
+layout(location = 1) out uvec4 FragColorUint;
+
+layout(push_constant, std140) uniform Push
+{
+ int8_t i8;
+ uint8_t u8;
+} registers;
+
+layout(binding = 0, std140) uniform UBO
+{
+ int8_t i8;
+ uint8_t u8;
+} ubo;
+
+layout(binding = 1, std430) buffer SSBO
+{
+ int8_t i8[16];
+ uint8_t u8[16];
+} ssbo;
+
+void packing_int8()
+{
+ int16_t i16 = 10s;
+ int i32 = 20;
+
+ i8vec2 i8_2 = unpack8(i16);
+ i8vec4 i8_4 = unpack8(i32);
+ i16 = pack16(i8_2);
+ i32 = pack32(i8_4);
+ ssbo.i8[0] = i8_4.x;
+ ssbo.i8[1] = i8_4.y;
+ ssbo.i8[2] = i8_4.z;
+ ssbo.i8[3] = i8_4.w;
+}
+
+void packing_uint8()
+{
+ uint16_t u16 = 10us;
+ uint u32 = 20u;
+
+ u8vec2 u8_2 = unpack8(u16);
+ u8vec4 u8_4 = unpack8(u32);
+ u16 = pack16(u8_2);
+ u32 = pack32(u8_4);
+
+ ssbo.u8[0] = u8_4.x;
+ ssbo.u8[1] = u8_4.y;
+ ssbo.u8[2] = u8_4.z;
+ ssbo.u8[3] = u8_4.w;
+}
+
+void compute_int8()
+{
+ i8vec4 tmp = i8vec4(vColor);
+ tmp += registers.i8;
+ tmp += int8_t(-40);
+ tmp += i8vec4(-50);
+ tmp += i8vec4(10, 20, 30, 40);
+ tmp += ssbo.i8[4];
+ tmp += ubo.i8;
+ FragColorInt = ivec4(tmp);
+}
+
+void compute_uint8()
+{
+ u8vec4 tmp = u8vec4(vColor);
+ tmp += registers.u8;
+ tmp += uint8_t(-40);
+ tmp += u8vec4(-50);
+ tmp += u8vec4(10, 20, 30, 40);
+ tmp += ssbo.u8[4];
+ tmp += ubo.u8;
+ FragColorUint = uvec4(tmp);
+}
+
+void main()
+{
+ packing_int8();
+ packing_uint8();
+ compute_int8();
+ compute_uint8();
+}
diff --git a/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag b/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag
new file mode 100644
index 00000000..d70b0dad
--- /dev/null
+++ b/shaders/vulkan/frag/shader-arithmetic-8bit.nocompat.vk.frag
@@ -0,0 +1,88 @@
+#version 450
+#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require
+#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require
+
+layout(location = 0) flat in ivec4 vColor;
+layout(location = 0) out ivec4 FragColorInt;
+layout(location = 1) out uvec4 FragColorUint;
+
+layout(push_constant, std140) uniform Push
+{
+ int8_t i8;
+ uint8_t u8;
+} registers;
+
+layout(binding = 0, std140) uniform UBO
+{
+ int8_t i8;
+ uint8_t u8;
+} ubo;
+
+layout(binding = 1, std430) buffer SSBO
+{
+ int8_t i8[16];
+ uint8_t u8[16];
+} ssbo;
+
+void packing_int8()
+{
+ int16_t i16 = 10s;
+ int i32 = 20;
+
+ i8vec2 i8_2 = unpack8(i16);
+ i8vec4 i8_4 = unpack8(i32);
+ i16 = pack16(i8_2);
+ i32 = pack32(i8_4);
+ ssbo.i8[0] = i8_4.x;
+ ssbo.i8[1] = i8_4.y;
+ ssbo.i8[2] = i8_4.z;
+ ssbo.i8[3] = i8_4.w;
+}
+
+void packing_uint8()
+{
+ uint16_t u16 = 10us;
+ uint u32 = 20u;
+
+ u8vec2 u8_2 = unpack8(u16);
+ u8vec4 u8_4 = unpack8(u32);
+ u16 = pack16(u8_2);
+ u32 = pack32(u8_4);
+
+ ssbo.u8[0] = u8_4.x;
+ ssbo.u8[1] = u8_4.y;
+ ssbo.u8[2] = u8_4.z;
+ ssbo.u8[3] = u8_4.w;
+}
+
+void compute_int8()
+{
+ i8vec4 tmp = i8vec4(vColor);
+ tmp += registers.i8;
+ tmp += int8_t(-40);
+ tmp += i8vec4(-50);
+ tmp += i8vec4(10, 20, 30, 40);
+ tmp += ssbo.i8[4];
+ tmp += ubo.i8;
+ FragColorInt = ivec4(tmp);
+}
+
+void compute_uint8()
+{
+ u8vec4 tmp = u8vec4(vColor);
+ tmp += registers.u8;
+ tmp += uint8_t(-40);
+ tmp += u8vec4(-50);
+ tmp += u8vec4(10, 20, 30, 40);
+ tmp += ssbo.u8[4];
+ tmp += ubo.u8;
+ FragColorUint = uvec4(tmp);
+}
+
+void main()
+{
+ packing_int8();
+ packing_uint8();
+ compute_int8();
+ compute_uint8();
+}
diff --git a/spirv_common.hpp b/spirv_common.hpp
index 6852542e..aa32142d 100644
--- a/spirv_common.hpp
+++ b/spirv_common.hpp
@@ -1047,6 +1047,16 @@ struct SPIRConstant : IVariant
return uint16_t(m.c[col].r[row].u32 & 0xffffu);
}
+ inline int8_t scalar_i8(uint32_t col = 0, uint32_t row = 0) const
+ {
+ return int8_t(m.c[col].r[row].u32 & 0xffu);
+ }
+
+ inline uint8_t scalar_u8(uint32_t col = 0, uint32_t row = 0) const
+ {
+ return uint8_t(m.c[col].r[row].u32 & 0xffu);
+ }
+
inline float scalar_f16(uint32_t col = 0, uint32_t row = 0) const
{
return f16_to_f32(scalar_u16(col, row));
@@ -1435,6 +1445,61 @@ static inline bool type_is_integral(const SPIRType &type)
type.basetype == SPIRType::UShort || type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt ||
type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64;
}
+
+static inline SPIRType::BaseType to_signed_basetype(uint32_t width)
+{
+ switch (width)
+ {
+ case 8:
+ return SPIRType::SByte;
+ case 16:
+ return SPIRType::Short;
+ case 32:
+ return SPIRType::Int;
+ case 64:
+ return SPIRType::Int64;
+ default:
+ SPIRV_CROSS_THROW("Invalid bit width.");
+ }
+}
+
+static inline SPIRType::BaseType to_unsigned_basetype(uint32_t width)
+{
+ switch (width)
+ {
+ case 8:
+ return SPIRType::UByte;
+ case 16:
+ return SPIRType::UShort;
+ case 32:
+ return SPIRType::UInt;
+ case 64:
+ return SPIRType::UInt64;
+ default:
+ SPIRV_CROSS_THROW("Invalid bit width.");
+ }
+}
+
+// Returns true if an arithmetic operation does not change behavior depending on signedness.
+static inline bool opcode_is_sign_invariant(spv::Op opcode)
+{
+ switch (opcode)
+ {
+ case spv::OpIEqual:
+ case spv::OpINotEqual:
+ case spv::OpISub:
+ case spv::OpIAdd:
+ case spv::OpIMul:
+ case spv::OpShiftLeftLogical:
+ case spv::OpBitwiseOr:
+ case spv::OpBitwiseXor:
+ case spv::OpBitwiseAnd:
+ return true;
+
+ default:
+ return false;
+ }
+}
} // namespace spirv_cross
#endif
diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp
index 1e6f23a3..8d10b992 100644
--- a/spirv_glsl.cpp
+++ b/spirv_glsl.cpp
@@ -149,27 +149,6 @@ string CompilerGLSL::sanitize_underscores(const string &str)
return res;
}
-// Returns true if an arithmetic operation does not change behavior depending on signedness.
-static bool glsl_opcode_is_sign_invariant(Op opcode)
-{
- switch (opcode)
- {
- case OpIEqual:
- case OpINotEqual:
- case OpISub:
- case OpIAdd:
- case OpIMul:
- case OpShiftLeftLogical:
- case OpBitwiseOr:
- case OpBitwiseXor:
- case OpBitwiseAnd:
- return true;
-
- default:
- return false;
- }
-}
-
static const char *to_pls_layout(PlsFormat format)
{
switch (format)
@@ -342,23 +321,31 @@ void CompilerGLSL::find_static_extensions()
if (!options.es && options.version < 400)
require_extension_internal("GL_ARB_gpu_shader_fp64");
}
-
- if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
+ else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64)
{
if (options.es)
SPIRV_CROSS_THROW("64-bit integers not supported in ES profile.");
if (!options.es)
require_extension_internal("GL_ARB_gpu_shader_int64");
}
-
- if (type.basetype == SPIRType::Half)
- require_extension_internal("GL_AMD_gpu_shader_half_float");
-
- if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
- require_extension_internal("GL_EXT_shader_8bit_storage");
-
- if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
- require_extension_internal("GL_AMD_gpu_shader_int16");
+ else if (type.basetype == SPIRType::Half)
+ {
+ require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_float16");
+ if (options.vulkan_semantics)
+ require_extension_internal("GL_EXT_shader_16bit_storage");
+ }
+ else if (type.basetype == SPIRType::SByte || type.basetype == SPIRType::UByte)
+ {
+ require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int8");
+ if (options.vulkan_semantics)
+ require_extension_internal("GL_EXT_shader_8bit_storage");
+ }
+ else if (type.basetype == SPIRType::Short || type.basetype == SPIRType::UShort)
+ {
+ require_extension_internal("GL_EXT_shader_explicit_arithmetic_types_int16");
+ if (options.vulkan_semantics)
+ require_extension_internal("GL_EXT_shader_16bit_storage");
+ }
});
auto &execution = get_entry_point();
@@ -508,7 +495,7 @@ void CompilerGLSL::emit_header()
for (auto &ext : forced_extensions)
{
- if (ext == "GL_AMD_gpu_shader_half_float")
+ if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16")
{
// Special case, this extension has a potential fallback to another vendor extension in normal GLSL.
// GL_AMD_gpu_shader_half_float is a superset, so try that first.
@@ -519,22 +506,27 @@ void CompilerGLSL::emit_header()
statement("#elif defined(GL_NV_gpu_shader5)");
statement("#extension GL_NV_gpu_shader5 : require");
}
- statement("#elif defined(GL_EXT_shader_16bit_storage)");
- statement("#extension GL_EXT_shader_16bit_storage : require");
+ else
+ {
+ statement("#elif defined(GL_EXT_shader_explicit_arithmetic_types_float16)");
+ statement("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
+ }
statement("#else");
statement("#error No extension available for FP16.");
statement("#endif");
}
- else if (ext == "GL_AMD_gpu_shader_int16")
+ else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16")
{
- // GL_AMD_gpu_shader_int16 is a superset, so try that first.
- statement("#if defined(GL_AMD_gpu_shader_int16)");
- statement("#extension GL_AMD_gpu_shader_int16 : require");
- statement("#elif defined(GL_EXT_shader_16bit_storage)");
- statement("#extension GL_EXT_shader_16bit_storage : require");
- statement("#else");
- statement("#error No extension available for Int16.");
- statement("#endif");
+ if (options.vulkan_semantics)
+ statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require");
+ else
+ {
+ statement("#if defined(GL_AMD_gpu_shader_int16)");
+ statement("#extension GL_AMD_gpu_shader_int16 : require");
+ statement("#else");
+ statement("#error No extension available for Int16.");
+ statement("#endif");
+ }
}
else
statement("#extension ", ext, " : require");
@@ -2799,14 +2791,38 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop)
SPIRV_CROSS_THROW("Unimplemented spec constant op.");
}
+ uint32_t bit_width = 0;
+ if (unary || binary)
+ bit_width = expression_type(cop.arguments[0]).width;
+
SPIRType::BaseType input_type;
- bool skip_cast_if_equal_type = glsl_opcode_is_sign_invariant(cop.opcode);
+ bool skip_cast_if_equal_type = opcode_is_sign_invariant(cop.opcode);
switch (cop.opcode)
{
case OpIEqual:
case OpINotEqual:
- input_type = SPIRType::Int;
+ input_type = to_signed_basetype(bit_width);
+ break;
+
+ case OpSLessThan:
+ case OpSLessThanEqual:
+ case OpSGreaterThan:
+ case OpSGreaterThanEqual:
+ case OpSMod:
+ case OpSDiv:
+ case OpShiftRightArithmetic:
+ input_type = to_signed_basetype(bit_width);
+ break;
+
+ case OpULessThan:
+ case OpULessThanEqual:
+ case OpUGreaterThan:
+ case OpUGreaterThanEqual:
+ case OpUMod:
+ case OpUDiv:
+ case OpShiftRightLogical:
+ input_type = to_unsigned_basetype(bit_width);
break;
default:
@@ -3121,6 +3137,9 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
auto type = get<SPIRType>(c.constant_type);
type.columns = 1;
+ auto scalar_type = type;
+ scalar_type.vecsize = 1;
+
string res;
bool splat = backend.use_constructor_splatting && c.vector_size() > 1;
bool swizzle_splat = backend.can_swizzle_scalar && c.vector_size() > 1;
@@ -3429,6 +3448,56 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t
}
break;
+ case SPIRType::UByte:
+ if (splat)
+ {
+ res += convert_to_string(c.scalar_u8(vector, 0));
+ }
+ else
+ {
+ for (uint32_t i = 0; i < c.vector_size(); i++)
+ {
+ if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
+ res += to_name(c.specialization_constant_id(vector, i));
+ else
+ {
+ res += type_to_glsl(scalar_type);
+ res += "(";
+ res += convert_to_string(c.scalar_u8(vector, i));
+ res += ")";
+ }
+
+ if (i + 1 < c.vector_size())
+ res += ", ";
+ }
+ }
+ break;
+
+ case SPIRType::SByte:
+ if (splat)
+ {
+ res += convert_to_string(c.scalar_i8(vector, 0));
+ }
+ else
+ {
+ for (uint32_t i = 0; i < c.vector_size(); i++)
+ {
+ if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0)
+ res += to_name(c.specialization_constant_id(vector, i));
+ else
+ {
+ res += type_to_glsl(scalar_type);
+ res += "(";
+ res += convert_to_string(c.scalar_i8(vector, i));
+ res += ")";
+ }
+
+ if (i + 1 < c.vector_size())
+ res += ", ";
+ }
+ }
+ break;
+
case SPIRType::Boolean:
if (splat)
res += c.scalar(vector, 0) ? "true" : "false";
@@ -5185,20 +5254,31 @@ case OpGroupNonUniform##op: \
string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
{
- if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Short)
- return type_to_glsl(out_type);
- else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
- return type_to_glsl(out_type);
- else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64)
+ assert(out_type.basetype != SPIRType::Boolean);
+ assert(in_type.basetype != SPIRType::Boolean);
+
+ if (out_type.basetype == in_type.basetype)
+ return "";
+
+ bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
+ bool same_size_cast = out_type.width == in_type.width;
+
+ // Trivial bitcast case, casts between integers.
+ if (integral_cast && same_size_cast)
return type_to_glsl(out_type);
- else if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
+
+ // Catch-all 8-bit arithmetic casts (GL_EXT_shader_explicit_arithmetic_types).
+ if (out_type.width == 8 && in_type.width >= 16 && integral_cast && in_type.vecsize == 1)
+ return "unpack8";
+ else if (in_type.width == 8 && out_type.width == 16 && integral_cast && out_type.vecsize == 1)
+ return "pack16";
+ else if (in_type.width == 8 && out_type.width == 32 && integral_cast && out_type.vecsize == 1)
+ return "pack32";
+
+ // Floating <-> Integer special casts. Just have to enumerate all cases. :(
+ // 16-bit, 32-bit and 64-bit floats.
+ if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float)
return "floatBitsToUint";
- else if (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::UShort)
- return type_to_glsl(out_type);
- else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt)
- return type_to_glsl(out_type);
- else if (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64)
- return type_to_glsl(out_type);
else if (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float)
return "floatBitsToInt";
else if (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt)
@@ -5221,7 +5301,9 @@ string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &i
return "int16BitsToFloat16";
else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort)
return "uint16BitsToFloat16";
- else if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
+
+ // And finally, some even more special purpose casts.
+ if (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::UInt && in_type.vecsize == 2)
return "packUint2x32";
else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1)
return "unpackFloat2x16";
@@ -5243,8 +5325,8 @@ string CompilerGLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &i
return "packUint4x16";
else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt64 && in_type.vecsize == 1)
return "unpackUint4x16";
- else
- return "";
+
+ return "";
}
string CompilerGLSL::bitcast_glsl(const SPIRType &result_type, uint32_t argument)
@@ -6662,6 +6744,35 @@ void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_ex
}
}
+uint32_t CompilerGLSL::get_integer_width_for_instruction(const Instruction &instr) const
+{
+ if (instr.length < 3)
+ return 32;
+
+ auto *ops = stream(instr);
+
+ switch (instr.op)
+ {
+ case OpIEqual:
+ case OpINotEqual:
+ case OpSLessThan:
+ case OpSLessThanEqual:
+ case OpSGreaterThan:
+ case OpSGreaterThanEqual:
+ return expression_type(ops[2]).width;
+
+ default:
+ {
+ // We can look at result type which is more robust.
+ auto *type = maybe_get<SPIRType>(ops[0]);
+ if (type && type_is_integral(*type))
+ return type->width;
+ else
+ return 32;
+ }
+ }
+}
+
void CompilerGLSL::emit_instruction(const Instruction &instruction)
{
auto ops = stream(instruction);
@@ -6670,16 +6781,21 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
#define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define GLSL_BOP_CAST(op, type) \
- emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, glsl_opcode_is_sign_invariant(opcode))
+ emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define GLSL_BFOP_CAST(op, type) \
- emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, glsl_opcode_is_sign_invariant(opcode))
+ emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define GLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
+ // If we need to do implicit bitcasts, make sure we do it with the correct type.
+ uint32_t integer_width = get_integer_width_for_instruction(instruction);
+ auto int_type = to_signed_basetype(integer_width);
+ auto uint_type = to_unsigned_basetype(integer_width);
+
switch (opcode)
{
// Dealing with memory
@@ -7357,11 +7473,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
}
case OpSDiv:
- GLSL_BOP_CAST(/, SPIRType::Int);
+ GLSL_BOP_CAST(/, int_type);
break;
case OpUDiv:
- GLSL_BOP_CAST(/, SPIRType::UInt);
+ GLSL_BOP_CAST(/, uint_type);
break;
case OpIAddCarry:
@@ -7419,11 +7535,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
break;
case OpShiftRightLogical:
- GLSL_BOP_CAST(>>, SPIRType::UInt);
+ GLSL_BOP_CAST(>>, uint_type);
break;
case OpShiftRightArithmetic:
- GLSL_BOP_CAST(>>, SPIRType::Int);
+ GLSL_BOP_CAST(>>, int_type);
break;
case OpShiftLeftLogical:
@@ -7459,11 +7575,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
break;
case OpUMod:
- GLSL_BOP_CAST(%, SPIRType::UInt);
+ GLSL_BOP_CAST(%, uint_type);
break;
case OpSMod:
- GLSL_BOP_CAST(%, SPIRType::Int);
+ GLSL_BOP_CAST(%, int_type);
break;
case OpFMod:
@@ -7546,9 +7662,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpIEqual:
{
if (expression_type(ops[2]).vecsize > 1)
- GLSL_BFOP_CAST(equal, SPIRType::Int);
+ GLSL_BFOP_CAST(equal, int_type);
else
- GLSL_BOP_CAST(==, SPIRType::Int);
+ GLSL_BOP_CAST(==, int_type);
break;
}
@@ -7565,9 +7681,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
case OpINotEqual:
{
if (expression_type(ops[2]).vecsize > 1)
- GLSL_BFOP_CAST(notEqual, SPIRType::Int);
+ GLSL_BFOP_CAST(notEqual, int_type);
else
- GLSL_BOP_CAST(!=, SPIRType::Int);
+ GLSL_BOP_CAST(!=, int_type);
break;
}
diff --git a/spirv_glsl.hpp b/spirv_glsl.hpp
index e19228c2..caf0ad3b 100644
--- a/spirv_glsl.hpp
+++ b/spirv_glsl.hpp
@@ -636,6 +636,8 @@ protected:
bool expression_is_constant_null(uint32_t id) const;
virtual void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression);
+ uint32_t get_integer_width_for_instruction(const Instruction &instr) const;
+
private:
void init()
{
diff --git a/spirv_hlsl.cpp b/spirv_hlsl.cpp
index b2102f1b..a5b6d2dc 100644
--- a/spirv_hlsl.cpp
+++ b/spirv_hlsl.cpp
@@ -203,27 +203,6 @@ static string image_format_to_type(ImageFormat fmt, SPIRType::BaseType basetype)
}
}
-// Returns true if an arithmetic operation does not change behavior depending on signedness.
-static bool hlsl_opcode_is_sign_invariant(Op opcode)
-{
- switch (opcode)
- {
- case OpIEqual:
- case OpINotEqual:
- case OpISub:
- case OpIAdd:
- case OpIMul:
- case OpShiftLeftLogical:
- case OpBitwiseOr:
- case OpBitwiseXor:
- case OpBitwiseAnd:
- return true;
-
- default:
- return false;
- }
-}
-
string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t)
{
auto &imagetype = get<SPIRType>(type.image.type);
@@ -3896,16 +3875,20 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
#define HLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define HLSL_BOP_CAST(op, type) \
- emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, hlsl_opcode_is_sign_invariant(opcode))
+ emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define HLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op)
#define HLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op)
#define HLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op)
#define HLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define HLSL_BFOP_CAST(op, type) \
- emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, hlsl_opcode_is_sign_invariant(opcode))
+ emit_binary_func_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
#define HLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op)
#define HLSL_UFOP(op) emit_unary_func_op(ops[0], ops[1], ops[2], #op)
+ // If we need to do implicit bitcasts, make sure we do it with the correct type.
+ uint32_t integer_width = get_integer_width_for_instruction(instruction);
+ auto int_type = to_signed_basetype(integer_width);
+
switch (opcode)
{
case OpAccessChain:
@@ -4041,7 +4024,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "==");
else
- HLSL_BOP_CAST(==, SPIRType::Int);
+ HLSL_BOP_CAST(==, int_type);
break;
}
@@ -4066,7 +4049,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
if (expression_type(ops[2]).vecsize > 1)
emit_unrolled_binary_op(result_type, id, ops[2], ops[3], "!=");
else
- HLSL_BOP_CAST(!=, SPIRType::Int);
+ HLSL_BOP_CAST(!=, int_type);
break;
}
diff --git a/spirv_msl.cpp b/spirv_msl.cpp
index 317b6c7e..5f2cc4f0 100644
--- a/spirv_msl.cpp
+++ b/spirv_msl.cpp
@@ -2441,7 +2441,6 @@ void CompilerMSL::emit_binary_unord_op(uint32_t result_type, uint32_t result_id,
// Override for MSL-specific syntax instructions
void CompilerMSL::emit_instruction(const Instruction &instruction)
{
-
#define MSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op)
#define MSL_BOP_CAST(op, type) \
emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode))
@@ -2457,42 +2456,77 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
auto ops = stream(instruction);
auto opcode = static_cast<Op>(instruction.op);
+ // If we need to do implicit bitcasts, make sure we do it with the correct type.
+ uint32_t integer_width = get_integer_width_for_instruction(instruction);
+ auto int_type = to_signed_basetype(integer_width);
+ auto uint_type = to_unsigned_basetype(integer_width);
+
switch (opcode)
{
// Comparisons
case OpIEqual:
+ MSL_BOP_CAST(==, int_type);
+ break;
+
case OpLogicalEqual:
case OpFOrdEqual:
MSL_BOP(==);
break;
case OpINotEqual:
+ MSL_BOP_CAST(!=, int_type);
+ break;
+
case OpLogicalNotEqual:
case OpFOrdNotEqual:
MSL_BOP(!=);
break;
case OpUGreaterThan:
+ MSL_BOP_CAST(>, uint_type);
+ break;
+
case OpSGreaterThan:
+ MSL_BOP_CAST(>, int_type);
+ break;
+
case OpFOrdGreaterThan:
MSL_BOP(>);
break;
case OpUGreaterThanEqual:
+ MSL_BOP_CAST(>=, uint_type);
+ break;
+
case OpSGreaterThanEqual:
+ MSL_BOP_CAST(>=, int_type);
+ break;
+
case OpFOrdGreaterThanEqual:
MSL_BOP(>=);
break;
case OpULessThan:
+ MSL_BOP_CAST(<, uint_type);
+ break;
+
case OpSLessThan:
+ MSL_BOP_CAST(<, int_type);
+ break;
+
case OpFOrdLessThan:
MSL_BOP(<);
break;
case OpULessThanEqual:
+ MSL_BOP_CAST(<=, uint_type);
+ break;
+
case OpSLessThanEqual:
+ MSL_BOP_CAST(<=, int_type);
+ break;
+
case OpFOrdLessThanEqual:
MSL_BOP(<=);
break;
@@ -5433,37 +5467,25 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
string CompilerMSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
{
- if ((out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Short) ||
- (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::UShort) ||
- (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int) ||
- (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::UInt) ||
- (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Int64) ||
- (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::UInt64))
- return type_to_glsl(out_type);
+ assert(out_type.basetype != SPIRType::Boolean);
+ assert(in_type.basetype != SPIRType::Boolean);
- if ((out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Float) ||
- (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Float) ||
- (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::UInt) ||
- (out_type.basetype == SPIRType::Float && in_type.basetype == SPIRType::Int) ||
- (out_type.basetype == SPIRType::Int64 && in_type.basetype == SPIRType::Double) ||
- (out_type.basetype == SPIRType::UInt64 && in_type.basetype == SPIRType::Double) ||
- (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::Int64) ||
- (out_type.basetype == SPIRType::Double && in_type.basetype == SPIRType::UInt64) ||
- (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UInt) ||
- (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Half) ||
- (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Int) ||
- (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Half) ||
- (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort) ||
- (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half) ||
- (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::Short) ||
- (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Half) ||
- (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::UShort && in_type.vecsize == 2) ||
- (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::UInt && in_type.vecsize == 1) ||
- (out_type.basetype == SPIRType::Int && in_type.basetype == SPIRType::Short && in_type.vecsize == 2) ||
- (out_type.basetype == SPIRType::Short && in_type.basetype == SPIRType::Int && in_type.vecsize == 1))
- return "as_type<" + type_to_glsl(out_type) + ">";
+ if (out_type.basetype == in_type.basetype)
+ return "";
- return "";
+ bool integral_cast = type_is_integral(out_type) && type_is_integral(in_type);
+ bool same_size_cast = out_type.width == in_type.width;
+
+ if (integral_cast && same_size_cast)
+ {
+ // Trivial bitcast case, casts between integers.
+ return type_to_glsl(out_type);
+ }
+ else
+ {
+ // Fall back to the catch-all bitcast in MSL.
+ return "as_type<" + type_to_glsl(out_type) + ">";
+ }
}
// Returns an MSL string identifying the name of a SPIR-V builtin.
diff --git a/spirv_parser.cpp b/spirv_parser.cpp
index 2f76144e..1725b4ca 100644
--- a/spirv_parser.cpp
+++ b/spirv_parser.cpp
@@ -461,23 +461,7 @@ void Parser::parse(const Instruction &instruction)
uint32_t width = ops[1];
bool signedness = ops[2] != 0;
auto &type = set<SPIRType>(id);
- switch (width)
- {
- case 64:
- type.basetype = signedness ? SPIRType::Int64 : SPIRType::UInt64;
- break;
- case 32:
- type.basetype = signedness ? SPIRType::Int : SPIRType::UInt;
- break;
- case 16:
- type.basetype = signedness ? SPIRType::Short : SPIRType::UShort;
- break;
- case 8:
- type.basetype = signedness ? SPIRType::SByte : SPIRType::UByte;
- break;
- default:
- SPIRV_CROSS_THROW("Unrecognized bit-width of integral type.");
- }
+ type.basetype = signedness ? to_signed_basetype(width) : to_unsigned_basetype(width);
type.width = width;
break;
}