MSL: Make builtin argument type declaration context sensitive.
authorHans-Kristian Arntzen <post@arntzen-software.no>
Fri, 16 Apr 2021 10:18:31 +0000 (12:18 +0200)
committerHans-Kristian Arntzen <post@arntzen-software.no>
Mon, 19 Apr 2021 10:10:49 +0000 (12:10 +0200)
Sometimes we'll need array template, sometimes not :shrug:.

reference/opt/shaders-msl/frag/read-cull-clip-distance-in-function.frag [new file with mode: 0644]
reference/shaders-msl/frag/read-cull-clip-distance-in-function.frag [new file with mode: 0644]
reference/shaders-msl/masking/write-outputs.mask-location-0.for-tess.vert
reference/shaders-msl/masking/write-outputs.mask-location-1.for-tess.vert
reference/shaders-msl/masking/write-outputs.mask-point-size.for-tess.vert
shaders-msl/frag/read-cull-clip-distance-in-function.frag [new file with mode: 0644]
spirv_msl.cpp

diff --git a/reference/opt/shaders-msl/frag/read-cull-clip-distance-in-function.frag b/reference/opt/shaders-msl/frag/read-cull-clip-distance-in-function.frag
new file mode 100644 (file)
index 0000000..3c9757e
--- /dev/null
@@ -0,0 +1,72 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+#pragma clang diagnostic ignored "-Wmissing-braces"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+template<typename T, size_t Num>
+struct spvUnsafeArray
+{
+    T elements[Num ? Num : 1];
+    
+    thread T& operator [] (size_t pos) thread
+    {
+        return elements[pos];
+    }
+    constexpr const thread T& operator [] (size_t pos) const thread
+    {
+        return elements[pos];
+    }
+    
+    device T& operator [] (size_t pos) device
+    {
+        return elements[pos];
+    }
+    constexpr const device T& operator [] (size_t pos) const device
+    {
+        return elements[pos];
+    }
+    
+    constexpr const constant T& operator [] (size_t pos) const constant
+    {
+        return elements[pos];
+    }
+    
+    threadgroup T& operator [] (size_t pos) threadgroup
+    {
+        return elements[pos];
+    }
+    constexpr const threadgroup T& operator [] (size_t pos) const threadgroup
+    {
+        return elements[pos];
+    }
+};
+
+struct main0_out
+{
+    float4 FragColor [[color(0)]];
+};
+
+struct main0_in
+{
+    float gl_ClipDistance_0 [[user(clip0)]];
+    float gl_ClipDistance_1 [[user(clip1)]];
+    float gl_CullDistance_0 [[user(cull0)]];
+    float gl_CullDistance_1 [[user(cull1)]];
+};
+
+fragment main0_out main0(main0_in in [[stage_in]])
+{
+    main0_out out = {};
+    spvUnsafeArray<float, 2> gl_CullDistance = {};
+    spvUnsafeArray<float, 2> gl_ClipDistance = {};
+    gl_CullDistance[0] = in.gl_CullDistance_0;
+    gl_CullDistance[1] = in.gl_CullDistance_1;
+    gl_ClipDistance[0] = in.gl_ClipDistance_0;
+    gl_ClipDistance[1] = in.gl_ClipDistance_1;
+    out.FragColor = float4(gl_CullDistance[0], gl_CullDistance[1], gl_ClipDistance[0], gl_ClipDistance[1]);
+    return out;
+}
+
diff --git a/reference/shaders-msl/frag/read-cull-clip-distance-in-function.frag b/reference/shaders-msl/frag/read-cull-clip-distance-in-function.frag
new file mode 100644 (file)
index 0000000..02d57d9
--- /dev/null
@@ -0,0 +1,78 @@
+#pragma clang diagnostic ignored "-Wmissing-prototypes"
+#pragma clang diagnostic ignored "-Wmissing-braces"
+
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+template<typename T, size_t Num>
+struct spvUnsafeArray
+{
+    T elements[Num ? Num : 1];
+    
+    thread T& operator [] (size_t pos) thread
+    {
+        return elements[pos];
+    }
+    constexpr const thread T& operator [] (size_t pos) const thread
+    {
+        return elements[pos];
+    }
+    
+    device T& operator [] (size_t pos) device
+    {
+        return elements[pos];
+    }
+    constexpr const device T& operator [] (size_t pos) const device
+    {
+        return elements[pos];
+    }
+    
+    constexpr const constant T& operator [] (size_t pos) const constant
+    {
+        return elements[pos];
+    }
+    
+    threadgroup T& operator [] (size_t pos) threadgroup
+    {
+        return elements[pos];
+    }
+    constexpr const threadgroup T& operator [] (size_t pos) const threadgroup
+    {
+        return elements[pos];
+    }
+};
+
+struct main0_out
+{
+    float4 FragColor [[color(0)]];
+};
+
+struct main0_in
+{
+    float gl_ClipDistance_0 [[user(clip0)]];
+    float gl_ClipDistance_1 [[user(clip1)]];
+    float gl_CullDistance_0 [[user(cull0)]];
+    float gl_CullDistance_1 [[user(cull1)]];
+};
+
+static inline __attribute__((always_inline))
+float4 read_in_func(thread spvUnsafeArray<float, 2>& gl_CullDistance, thread spvUnsafeArray<float, 2>& gl_ClipDistance)
+{
+    return float4(gl_CullDistance[0], gl_CullDistance[1], gl_ClipDistance[0], gl_ClipDistance[1]);
+}
+
+fragment main0_out main0(main0_in in [[stage_in]])
+{
+    main0_out out = {};
+    spvUnsafeArray<float, 2> gl_CullDistance = {};
+    spvUnsafeArray<float, 2> gl_ClipDistance = {};
+    gl_CullDistance[0] = in.gl_CullDistance_0;
+    gl_CullDistance[1] = in.gl_CullDistance_1;
+    gl_ClipDistance[0] = in.gl_ClipDistance_0;
+    gl_ClipDistance[1] = in.gl_ClipDistance_1;
+    out.FragColor = read_in_func(gl_CullDistance, gl_ClipDistance);
+    return out;
+}
+
index a004a38..53f76b5 100644 (file)
@@ -53,7 +53,7 @@ struct main0_out
 };
 
 static inline __attribute__((always_inline))
-void write_in_func(thread float4& v0, device float4& v1, device float4& gl_Position, device float& gl_PointSize, device float (&gl_ClipDistance)[2])
+void write_in_func(thread float4& v0, device float4& v1, device float4& gl_Position, device float& gl_PointSize, device spvUnsafeArray<float, 2>& gl_ClipDistance)
 {
     v0 = float4(1.0);
     v1 = float4(2.0);
index 0228882..8f9cfce 100644 (file)
@@ -53,7 +53,7 @@ struct main0_out
 };
 
 static inline __attribute__((always_inline))
-void write_in_func(device float4& v0, thread float4& v1, device float4& gl_Position, device float& gl_PointSize, device float (&gl_ClipDistance)[2])
+void write_in_func(device float4& v0, thread float4& v1, device float4& gl_Position, device float& gl_PointSize, device spvUnsafeArray<float, 2>& gl_ClipDistance)
 {
     v0 = float4(1.0);
     v1 = float4(2.0);
index 1307b5b..07494ea 100644 (file)
@@ -53,7 +53,7 @@ struct main0_out
 };
 
 static inline __attribute__((always_inline))
-void write_in_func(device float4& v0, device float4& v1, device float4& gl_Position, thread float& gl_PointSize, device float (&gl_ClipDistance)[2])
+void write_in_func(device float4& v0, device float4& v1, device float4& gl_Position, thread float& gl_PointSize, device spvUnsafeArray<float, 2>& gl_ClipDistance)
 {
     v0 = float4(1.0);
     v1 = float4(2.0);
diff --git a/shaders-msl/frag/read-cull-clip-distance-in-function.frag b/shaders-msl/frag/read-cull-clip-distance-in-function.frag
new file mode 100644 (file)
index 0000000..0b82dc2
--- /dev/null
@@ -0,0 +1,20 @@
+#version 450
+
+layout(location = 0) out vec4 FragColor;
+
+in float gl_CullDistance[2];
+in float gl_ClipDistance[2];
+
+vec4 read_in_func()
+{
+       return vec4(
+                       gl_CullDistance[0],
+                       gl_CullDistance[1],
+                       gl_ClipDistance[0],
+                       gl_ClipDistance[1]);
+}
+
+void main()
+{
+       FragColor = read_in_func();
+}
index f13e845..3c9338f 100644 (file)
@@ -12387,7 +12387,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
        auto &var = get<SPIRVariable>(arg.id);
        auto &type = get_variable_data_type(var);
        auto &var_type = get<SPIRType>(arg.type);
-       StorageClass storage = var_type.storage;
+       StorageClass type_storage = var_type.storage;
        bool is_pointer = var_type.pointer;
 
        // If we need to modify the name of the variable, make sure we use the original variable.
@@ -12424,15 +12424,30 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
        string address_space = get_argument_address_space(var);
        bool builtin = has_decoration(var.self, DecorationBuiltIn);
        auto builtin_type = BuiltIn(get_decoration(arg.id, DecorationBuiltIn));
-       is_using_builtin_array = builtin;
+
        if (address_space == "threadgroup")
                is_using_builtin_array = true;
 
        if (var.basevariable && (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id))
                decl = join(cv_qualifier, type_to_glsl(type, arg.id));
        else if (builtin)
-               decl = join(cv_qualifier, builtin_type_decl(builtin_type, arg.id));
-       else if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) && is_array(type))
+       {
+               // Only use templated array for Clip/Cull distance when feasible.
+               // In other scenarios, we need need to override array length for tess levels,
+               // or we need to emit the expected type for builtins (uint vs int).
+               if (builtin_type != BuiltInClipDistance && builtin_type != BuiltInCullDistance)
+                       is_using_builtin_array = true;
+
+               auto storage = get<SPIRType>(var.basetype).storage;
+               if (storage == StorageClassOutput && variable_storage_requires_stage_io(storage))
+                       is_using_builtin_array = true;
+
+               if (is_using_builtin_array)
+                       decl = join(cv_qualifier, builtin_type_decl(builtin_type, arg.id));
+               else
+                       decl = join(cv_qualifier, type_to_glsl(type, arg.id));
+       }
+       else if ((type_storage == StorageClassUniform || type_storage == StorageClassStorageBuffer) && is_array(type))
        {
                is_using_builtin_array = true;
                decl += join(cv_qualifier, type_to_glsl(type, arg.id), "*");
@@ -12456,10 +12471,10 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
                        decl = join(cv_qualifier, type_to_glsl(type, arg.id));
        }
 
-       bool opaque_handle = storage == StorageClassUniformConstant;
+       bool opaque_handle = type_storage == StorageClassUniformConstant;
 
        if (!builtin && !opaque_handle && !is_pointer &&
-           (storage == StorageClassFunction || storage == StorageClassGeneric))
+           (type_storage == StorageClassFunction || type_storage == StorageClassGeneric))
        {
                // If the argument is a pure value and not an opaque type, we will pass by value.
                if (msl_options.force_native_arrays && is_array(type))
@@ -12500,7 +12515,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
                if (msl_options.argument_buffers)
                {
                        uint32_t desc_set = get_decoration(name_id, DecorationDescriptorSet);
-                       if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) &&
+                       if ((type_storage == StorageClassUniform || type_storage == StorageClassStorageBuffer) &&
                            descriptor_set_is_argument_buffer(desc_set))
                        {
                                // An awkward case where we need to emit *more* address space declarations (yay!).
@@ -14226,6 +14241,7 @@ string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id)
 
        // Vertex function out
        case BuiltInClipDistance:
+       case BuiltInCullDistance:
                return "float";
        case BuiltInPointSize:
                return "float";