Sometimes we'll need array template, sometimes not :shrug:.
--- /dev/null
+#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;
+}
+
--- /dev/null
+#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;
+}
+
};
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);
};
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);
};
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);
--- /dev/null
+#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();
+}
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.
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), "*");
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))
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!).
// Vertex function out
case BuiltInClipDistance:
+ case BuiltInCullDistance:
return "float";
case BuiltInPointSize:
return "float";