MSL: Support SPV_KHR_multiview.
This is needed to support `VK_KHR_multiview`, which is in turn needed for Vulkan 1.1 support. Unfortunately, Metal provides no native support for this, and Apple is once again less than forthcoming, so we have to implement it all ourselves. Tessellation and geometry shaders are deliberately unsupported for now. The problem is that the current implementation encodes the `ViewIndex` as part of the `InstanceIndex`, which in the SPIR-V environment at least only exists in the vertex shader. So we need to work out a way to pass the view index along to the later stages. This implementation runs vertex shaders for all views up to the highest bit set in the view mask, even those whose bits are clear. The fragments for the inactive views are then discarded. Avoiding this is difficult: calculating the view indices becomes far more complicated if we can only run for those views which are set in the mask.
This commit is contained in:
parent
8ee8e60f70
commit
7eecf5a46b
4
main.cpp
4
main.cpp
@ -514,6 +514,7 @@ struct CLIArguments
|
|||||||
bool msl_domain_lower_left = false;
|
bool msl_domain_lower_left = false;
|
||||||
bool msl_argument_buffers = false;
|
bool msl_argument_buffers = false;
|
||||||
bool msl_texture_buffer_native = false;
|
bool msl_texture_buffer_native = false;
|
||||||
|
bool msl_multiview = false;
|
||||||
bool glsl_emit_push_constant_as_ubo = false;
|
bool glsl_emit_push_constant_as_ubo = false;
|
||||||
bool glsl_emit_ubo_as_plain_uniforms = false;
|
bool glsl_emit_ubo_as_plain_uniforms = false;
|
||||||
bool emit_line_directives = false;
|
bool emit_line_directives = false;
|
||||||
@ -592,6 +593,7 @@ static void print_help()
|
|||||||
"\t[--msl-argument-buffers]\n"
|
"\t[--msl-argument-buffers]\n"
|
||||||
"\t[--msl-texture-buffer-native]\n"
|
"\t[--msl-texture-buffer-native]\n"
|
||||||
"\t[--msl-discrete-descriptor-set <index>]\n"
|
"\t[--msl-discrete-descriptor-set <index>]\n"
|
||||||
|
"\t[--msl-multiview]\n"
|
||||||
"\t[--hlsl]\n"
|
"\t[--hlsl]\n"
|
||||||
"\t[--reflect]\n"
|
"\t[--reflect]\n"
|
||||||
"\t[--shader-model]\n"
|
"\t[--shader-model]\n"
|
||||||
@ -750,6 +752,7 @@ static string compile_iteration(const CLIArguments &args, std::vector<uint32_t>
|
|||||||
msl_opts.tess_domain_origin_lower_left = args.msl_domain_lower_left;
|
msl_opts.tess_domain_origin_lower_left = args.msl_domain_lower_left;
|
||||||
msl_opts.argument_buffers = args.msl_argument_buffers;
|
msl_opts.argument_buffers = args.msl_argument_buffers;
|
||||||
msl_opts.texture_buffer_native = args.msl_texture_buffer_native;
|
msl_opts.texture_buffer_native = args.msl_texture_buffer_native;
|
||||||
|
msl_opts.multiview = args.msl_multiview;
|
||||||
msl_comp->set_msl_options(msl_opts);
|
msl_comp->set_msl_options(msl_opts);
|
||||||
for (auto &v : args.msl_discrete_descriptor_sets)
|
for (auto &v : args.msl_discrete_descriptor_sets)
|
||||||
msl_comp->add_discrete_descriptor_set(v);
|
msl_comp->add_discrete_descriptor_set(v);
|
||||||
@ -1069,6 +1072,7 @@ static int main_inner(int argc, char *argv[])
|
|||||||
cbs.add("--msl-discrete-descriptor-set",
|
cbs.add("--msl-discrete-descriptor-set",
|
||||||
[&args](CLIParser &parser) { args.msl_discrete_descriptor_sets.push_back(parser.next_uint()); });
|
[&args](CLIParser &parser) { args.msl_discrete_descriptor_sets.push_back(parser.next_uint()); });
|
||||||
cbs.add("--msl-texture-buffer-native", [&args](CLIParser &) { args.msl_texture_buffer_native = true; });
|
cbs.add("--msl-texture-buffer-native", [&args](CLIParser &) { args.msl_texture_buffer_native = true; });
|
||||||
|
cbs.add("--msl-multiview", [&args](CLIParser &) { args.msl_multiview = true; });
|
||||||
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); });
|
||||||
cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
|
cbs.add("--rename-entry-point", [&args](CLIParser &parser) {
|
||||||
auto old_name = parser.next_string();
|
auto old_name = parser.next_string();
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 FragColor [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 vColor [[user(locn0)]];
|
||||||
|
float2 vTex_0 [[user(locn1)]];
|
||||||
|
float2 vTex_1 [[user(locn2)]];
|
||||||
|
float2 vTex_2 [[user(locn3)]];
|
||||||
|
float2 vTex_3 [[user(locn4)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], texture2d<float> uTex [[texture(0)]], sampler uTexSmplr [[sampler(0)]], uint gl_ViewIndex [[render_target_array_index]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 vTex[4] = {};
|
||||||
|
vTex[0] = in.vTex_0;
|
||||||
|
vTex[1] = in.vTex_1;
|
||||||
|
vTex[2] = in.vTex_2;
|
||||||
|
vTex[3] = in.vTex_3;
|
||||||
|
gl_ViewIndex += spvViewMask[0];
|
||||||
|
out.FragColor = in.vColor * uTex.sample(uTexSmplr, vTex[int(gl_ViewIndex)]);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct MVPs
|
||||||
|
{
|
||||||
|
float4x4 MVP[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
uint gl_Layer [[render_target_array_index]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 Position [[attribute(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], constant MVPs& _19 [[buffer(0)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
uint gl_ViewIndex = spvViewMask[0] + gl_InstanceIndex % spvViewMask[1];
|
||||||
|
gl_InstanceIndex /= spvViewMask[1];
|
||||||
|
out.gl_Position = _19.MVP[int(gl_ViewIndex)] * in.Position;
|
||||||
|
out.gl_Layer = gl_ViewIndex - spvViewMask[0];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct MVPs
|
||||||
|
{
|
||||||
|
float4x4 MVP[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
uint gl_Layer [[render_target_array_index]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 Position [[attribute(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant MVPs& _19 [[buffer(0)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
const uint gl_ViewIndex = 0;
|
||||||
|
out.gl_Position = _19.MVP[int(gl_ViewIndex)] * in.Position;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 FragColor [[color(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 vColor [[user(locn0)]];
|
||||||
|
float2 vTex_0 [[user(locn1)]];
|
||||||
|
float2 vTex_1 [[user(locn2)]];
|
||||||
|
float2 vTex_2 [[user(locn3)]];
|
||||||
|
float2 vTex_3 [[user(locn4)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
fragment main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], texture2d<float> uTex [[texture(0)]], sampler uTexSmplr [[sampler(0)]], uint gl_ViewIndex [[render_target_array_index]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
float2 vTex[4] = {};
|
||||||
|
vTex[0] = in.vTex_0;
|
||||||
|
vTex[1] = in.vTex_1;
|
||||||
|
vTex[2] = in.vTex_2;
|
||||||
|
vTex[3] = in.vTex_3;
|
||||||
|
gl_ViewIndex += spvViewMask[0];
|
||||||
|
out.FragColor = in.vColor * uTex.sample(uTexSmplr, vTex[int(gl_ViewIndex)]);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct MVPs
|
||||||
|
{
|
||||||
|
float4x4 MVP[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
uint gl_Layer [[render_target_array_index]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 Position [[attribute(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant uint* spvViewMask [[buffer(24)]], constant MVPs& _19 [[buffer(0)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
uint gl_ViewIndex = spvViewMask[0] + gl_InstanceIndex % spvViewMask[1];
|
||||||
|
gl_InstanceIndex /= spvViewMask[1];
|
||||||
|
out.gl_Position = _19.MVP[int(gl_ViewIndex)] * in.Position;
|
||||||
|
out.gl_Layer = gl_ViewIndex - spvViewMask[0];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
29
reference/shaders-msl/vulkan/vert/multiview.nocompat.vk.vert
Normal file
29
reference/shaders-msl/vulkan/vert/multiview.nocompat.vk.vert
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <metal_stdlib>
|
||||||
|
#include <simd/simd.h>
|
||||||
|
|
||||||
|
using namespace metal;
|
||||||
|
|
||||||
|
struct MVPs
|
||||||
|
{
|
||||||
|
float4x4 MVP[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_out
|
||||||
|
{
|
||||||
|
float4 gl_Position [[position]];
|
||||||
|
uint gl_Layer [[render_target_array_index]];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct main0_in
|
||||||
|
{
|
||||||
|
float4 Position [[attribute(0)]];
|
||||||
|
};
|
||||||
|
|
||||||
|
vertex main0_out main0(main0_in in [[stage_in]], constant MVPs& _19 [[buffer(0)]], uint gl_InstanceIndex [[instance_id]])
|
||||||
|
{
|
||||||
|
main0_out out = {};
|
||||||
|
const uint gl_ViewIndex = 0;
|
||||||
|
out.gl_Position = _19.MVP[int(gl_ViewIndex)] * in.Position;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
14
shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag
Normal file
14
shaders-msl/vulkan/frag/basic.multiview.nocompat.vk.frag
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#version 310 es
|
||||||
|
#extension GL_EXT_multiview : require
|
||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 vColor;
|
||||||
|
layout(location = 1) in vec2 vTex[4];
|
||||||
|
layout(binding = 0) uniform sampler2D uTex;
|
||||||
|
layout(location = 0) out vec4 FragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
FragColor = vColor * texture(uTex, vTex[gl_ViewIndex]);
|
||||||
|
}
|
||||||
|
|
14
shaders-msl/vulkan/vert/multiview.multiview.nocompat.vk.vert
Normal file
14
shaders-msl/vulkan/vert/multiview.multiview.nocompat.vk.vert
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#version 310 es
|
||||||
|
#extension GL_EXT_multiview : require
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform MVPs
|
||||||
|
{
|
||||||
|
mat4 MVP[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = MVP[gl_ViewIndex] * Position;
|
||||||
|
}
|
14
shaders-msl/vulkan/vert/multiview.nocompat.vk.vert
Normal file
14
shaders-msl/vulkan/vert/multiview.nocompat.vk.vert
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#version 310 es
|
||||||
|
#extension GL_EXT_multiview : require
|
||||||
|
|
||||||
|
layout(std140, binding = 0) uniform MVPs
|
||||||
|
{
|
||||||
|
mat4 MVP[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
layout(location = 0) in vec4 Position;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = MVP[gl_ViewIndex] * Position;
|
||||||
|
}
|
135
spirv_msl.cpp
135
spirv_msl.cpp
@ -105,8 +105,10 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
active_input_builtins.get(BuiltInSubgroupLtMask);
|
active_input_builtins.get(BuiltInSubgroupLtMask);
|
||||||
bool need_subgroup_ge_mask = !msl_options.is_ios() && (active_input_builtins.get(BuiltInSubgroupGeMask) ||
|
bool need_subgroup_ge_mask = !msl_options.is_ios() && (active_input_builtins.get(BuiltInSubgroupGeMask) ||
|
||||||
active_input_builtins.get(BuiltInSubgroupGtMask));
|
active_input_builtins.get(BuiltInSubgroupGtMask));
|
||||||
|
bool need_multiview = get_execution_model() == ExecutionModelVertex &&
|
||||||
|
(msl_options.multiview || active_input_builtins.get(BuiltInViewIndex));
|
||||||
if (need_subpass_input || need_sample_pos || need_subgroup_mask || need_vertex_params || need_tesc_params ||
|
if (need_subpass_input || need_sample_pos || need_subgroup_mask || need_vertex_params || need_tesc_params ||
|
||||||
needs_subgroup_invocation_id)
|
need_multiview || needs_subgroup_invocation_id)
|
||||||
{
|
{
|
||||||
bool has_frag_coord = false;
|
bool has_frag_coord = false;
|
||||||
bool has_sample_id = false;
|
bool has_sample_id = false;
|
||||||
@ -118,6 +120,7 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
bool has_primitive_id = false;
|
bool has_primitive_id = false;
|
||||||
bool has_subgroup_invocation_id = false;
|
bool has_subgroup_invocation_id = false;
|
||||||
bool has_subgroup_size = false;
|
bool has_subgroup_size = false;
|
||||||
|
bool has_view_idx = false;
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
||||||
if (var.storage != StorageClassInput || !ir.meta[var.self].decoration.builtin)
|
if (var.storage != StorageClassInput || !ir.meta[var.self].decoration.builtin)
|
||||||
@ -189,6 +192,22 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
builtin_subgroup_size_id = var.self;
|
builtin_subgroup_size_id = var.self;
|
||||||
has_subgroup_size = true;
|
has_subgroup_size = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (need_multiview)
|
||||||
|
{
|
||||||
|
if (builtin == BuiltInInstanceIndex)
|
||||||
|
{
|
||||||
|
// The view index here is derived from the instance index.
|
||||||
|
builtin_instance_idx_id = var.self;
|
||||||
|
has_instance_idx = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (builtin == BuiltInViewIndex)
|
||||||
|
{
|
||||||
|
builtin_view_idx_id = var.self;
|
||||||
|
has_view_idx = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!has_frag_coord && need_subpass_input)
|
if (!has_frag_coord && need_subpass_input)
|
||||||
@ -246,7 +265,8 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
mark_implicit_builtin(StorageClassInput, BuiltInSampleId, var_id);
|
mark_implicit_builtin(StorageClassInput, BuiltInSampleId, var_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_vertex_params && (!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance))
|
if ((need_vertex_params && (!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance)) ||
|
||||||
|
(need_multiview && (!has_instance_idx || !has_view_idx)))
|
||||||
{
|
{
|
||||||
uint32_t offset = ir.increase_bound_by(2);
|
uint32_t offset = ir.increase_bound_by(2);
|
||||||
uint32_t type_id = offset;
|
uint32_t type_id = offset;
|
||||||
@ -265,7 +285,7 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
auto &ptr_type = set<SPIRType>(type_ptr_id, uint_type_ptr);
|
auto &ptr_type = set<SPIRType>(type_ptr_id, uint_type_ptr);
|
||||||
ptr_type.self = type_id;
|
ptr_type.self = type_id;
|
||||||
|
|
||||||
if (!has_vertex_idx)
|
if (need_vertex_params && !has_vertex_idx)
|
||||||
{
|
{
|
||||||
uint32_t var_id = ir.increase_bound_by(1);
|
uint32_t var_id = ir.increase_bound_by(1);
|
||||||
|
|
||||||
@ -276,7 +296,7 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
mark_implicit_builtin(StorageClassInput, BuiltInVertexIndex, var_id);
|
mark_implicit_builtin(StorageClassInput, BuiltInVertexIndex, var_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_base_vertex)
|
if (need_vertex_params && !has_base_vertex)
|
||||||
{
|
{
|
||||||
uint32_t var_id = ir.increase_bound_by(1);
|
uint32_t var_id = ir.increase_bound_by(1);
|
||||||
|
|
||||||
@ -287,7 +307,7 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
mark_implicit_builtin(StorageClassInput, BuiltInBaseVertex, var_id);
|
mark_implicit_builtin(StorageClassInput, BuiltInBaseVertex, var_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_instance_idx)
|
if (!has_instance_idx) // Needed by both multiview and tessellation
|
||||||
{
|
{
|
||||||
uint32_t var_id = ir.increase_bound_by(1);
|
uint32_t var_id = ir.increase_bound_by(1);
|
||||||
|
|
||||||
@ -296,9 +316,30 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
set_decoration(var_id, DecorationBuiltIn, BuiltInInstanceIndex);
|
set_decoration(var_id, DecorationBuiltIn, BuiltInInstanceIndex);
|
||||||
builtin_instance_idx_id = var_id;
|
builtin_instance_idx_id = var_id;
|
||||||
mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var_id);
|
mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var_id);
|
||||||
|
|
||||||
|
if (need_multiview)
|
||||||
|
{
|
||||||
|
// Multiview shaders are not allowed to write to gl_Layer, ostensibly because
|
||||||
|
// it is implicitly written from gl_ViewIndex, but we have to do that explicitly.
|
||||||
|
// Note that we can't just abuse gl_ViewIndex for this purpose: it's an input, but
|
||||||
|
// gl_Layer is an output in vertex-pipeline shaders.
|
||||||
|
uint32_t type_ptr_out_id = ir.increase_bound_by(2);
|
||||||
|
SPIRType uint_type_ptr_out;
|
||||||
|
uint_type_ptr_out = uint_type;
|
||||||
|
uint_type_ptr_out.pointer = true;
|
||||||
|
uint_type_ptr_out.parent_type = type_id;
|
||||||
|
uint_type_ptr_out.storage = StorageClassOutput;
|
||||||
|
auto &ptr_out_type = set<SPIRType>(type_ptr_out_id, uint_type_ptr_out);
|
||||||
|
ptr_out_type.self = type_id;
|
||||||
|
var_id = type_ptr_out_id + 1;
|
||||||
|
set<SPIRVariable>(var_id, type_ptr_out_id, StorageClassOutput);
|
||||||
|
set_decoration(var_id, DecorationBuiltIn, BuiltInLayer);
|
||||||
|
builtin_layer_id = var_id;
|
||||||
|
mark_implicit_builtin(StorageClassOutput, BuiltInLayer, var_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_base_instance)
|
if (need_vertex_params && !has_base_instance)
|
||||||
{
|
{
|
||||||
uint32_t var_id = ir.increase_bound_by(1);
|
uint32_t var_id = ir.increase_bound_by(1);
|
||||||
|
|
||||||
@ -308,6 +349,17 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
builtin_base_instance_id = var_id;
|
builtin_base_instance_id = var_id;
|
||||||
mark_implicit_builtin(StorageClassInput, BuiltInBaseInstance, var_id);
|
mark_implicit_builtin(StorageClassInput, BuiltInBaseInstance, var_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (need_multiview && !has_view_idx)
|
||||||
|
{
|
||||||
|
uint32_t var_id = ir.increase_bound_by(1);
|
||||||
|
|
||||||
|
// Create gl_ViewIndex.
|
||||||
|
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
|
||||||
|
set_decoration(var_id, DecorationBuiltIn, BuiltInViewIndex);
|
||||||
|
builtin_view_idx_id = var_id;
|
||||||
|
mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_tesc_params && (!has_invocation_id || !has_primitive_id))
|
if (need_tesc_params && (!has_invocation_id || !has_primitive_id))
|
||||||
@ -428,6 +480,17 @@ void CompilerMSL::build_implicit_builtins()
|
|||||||
set_extended_decoration(var_id, SPIRVCrossDecorationResourceIndexPrimary, msl_options.buffer_size_buffer_index);
|
set_extended_decoration(var_id, SPIRVCrossDecorationResourceIndexPrimary, msl_options.buffer_size_buffer_index);
|
||||||
buffer_size_buffer_id = var_id;
|
buffer_size_buffer_id = var_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needs_view_mask_buffer())
|
||||||
|
{
|
||||||
|
uint32_t var_id = build_constant_uint_array_pointer();
|
||||||
|
set_name(var_id, "spvViewMask");
|
||||||
|
// This should never match anything.
|
||||||
|
set_decoration(var_id, DecorationDescriptorSet, ~(4u));
|
||||||
|
set_decoration(var_id, DecorationBinding, msl_options.view_mask_buffer_index);
|
||||||
|
set_extended_decoration(var_id, SPIRVCrossDecorationResourceIndexPrimary, msl_options.view_mask_buffer_index);
|
||||||
|
view_mask_buffer_id = var_id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerMSL::mark_implicit_builtin(StorageClass storage, BuiltIn builtin, uint32_t id)
|
void CompilerMSL::mark_implicit_builtin(StorageClass storage, BuiltIn builtin, uint32_t id)
|
||||||
@ -732,6 +795,10 @@ string CompilerMSL::compile()
|
|||||||
active_interface_variables.insert(swizzle_buffer_id);
|
active_interface_variables.insert(swizzle_buffer_id);
|
||||||
if (buffer_size_buffer_id)
|
if (buffer_size_buffer_id)
|
||||||
active_interface_variables.insert(buffer_size_buffer_id);
|
active_interface_variables.insert(buffer_size_buffer_id);
|
||||||
|
if (view_mask_buffer_id)
|
||||||
|
active_interface_variables.insert(view_mask_buffer_id);
|
||||||
|
if (builtin_layer_id)
|
||||||
|
active_interface_variables.insert(builtin_layer_id);
|
||||||
|
|
||||||
// Create structs to hold input, output and uniform variables.
|
// Create structs to hold input, output and uniform variables.
|
||||||
// Do output first to ensure out. is declared at top of entry function.
|
// Do output first to ensure out. is declared at top of entry function.
|
||||||
@ -5700,6 +5767,10 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
|
|||||||
{
|
{
|
||||||
switch (builtin)
|
switch (builtin)
|
||||||
{
|
{
|
||||||
|
case BuiltInViewIndex:
|
||||||
|
if (!msl_options.multiview)
|
||||||
|
break;
|
||||||
|
/* fallthrough */
|
||||||
case BuiltInFrontFacing:
|
case BuiltInFrontFacing:
|
||||||
case BuiltInPointCoord:
|
case BuiltInPointCoord:
|
||||||
case BuiltInFragCoord:
|
case BuiltInFragCoord:
|
||||||
@ -6087,7 +6158,9 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args)
|
|||||||
bi_type != BuiltInClipDistance && bi_type != BuiltInCullDistance && bi_type != BuiltInSubgroupEqMask &&
|
bi_type != BuiltInClipDistance && bi_type != BuiltInCullDistance && bi_type != BuiltInSubgroupEqMask &&
|
||||||
bi_type != BuiltInBaryCoordNV && bi_type != BuiltInBaryCoordNoPerspNV &&
|
bi_type != BuiltInBaryCoordNV && bi_type != BuiltInBaryCoordNoPerspNV &&
|
||||||
bi_type != BuiltInSubgroupGeMask && bi_type != BuiltInSubgroupGtMask &&
|
bi_type != BuiltInSubgroupGeMask && bi_type != BuiltInSubgroupGtMask &&
|
||||||
bi_type != BuiltInSubgroupLeMask && bi_type != BuiltInSubgroupLtMask)
|
bi_type != BuiltInSubgroupLeMask && bi_type != BuiltInSubgroupLtMask &&
|
||||||
|
((get_execution_model() == ExecutionModelFragment && msl_options.multiview) ||
|
||||||
|
bi_type != BuiltInViewIndex))
|
||||||
{
|
{
|
||||||
if (!ep_args.empty())
|
if (!ep_args.empty())
|
||||||
ep_args += ", ";
|
ep_args += ", ";
|
||||||
@ -6582,6 +6655,44 @@ void CompilerMSL::fix_up_shader_inputs_outputs()
|
|||||||
to_expression(builtin_subgroup_invocation_id_id), " - 32, 0)), uint2(0));");
|
to_expression(builtin_subgroup_invocation_id_id), " - 32, 0)), uint2(0));");
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
case BuiltInViewIndex:
|
||||||
|
if (!msl_options.multiview)
|
||||||
|
{
|
||||||
|
// According to the Vulkan spec, when not running under a multiview
|
||||||
|
// render pass, ViewIndex is 0.
|
||||||
|
entry_func.fixup_hooks_in.push_back([=]() {
|
||||||
|
statement("const ", builtin_type_decl(bi_type), " ", to_expression(var_id), " = 0;");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (get_execution_model() == ExecutionModelFragment)
|
||||||
|
{
|
||||||
|
// Because we adjusted the view index in the vertex shader, we have to
|
||||||
|
// adjust it back here.
|
||||||
|
entry_func.fixup_hooks_in.push_back([=]() {
|
||||||
|
statement(to_expression(var_id), " += ", to_expression(view_mask_buffer_id), "[0];");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (get_execution_model() == ExecutionModelVertex)
|
||||||
|
{
|
||||||
|
// Metal provides no special support for multiview, so we smuggle
|
||||||
|
// the view index in the instance index.
|
||||||
|
entry_func.fixup_hooks_in.push_back([=]() {
|
||||||
|
statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ",
|
||||||
|
to_expression(view_mask_buffer_id), "[0] + ", to_expression(builtin_instance_idx_id),
|
||||||
|
" % ", to_expression(view_mask_buffer_id), "[1];");
|
||||||
|
statement(to_expression(builtin_instance_idx_id), " /= ", to_expression(view_mask_buffer_id),
|
||||||
|
"[1];");
|
||||||
|
});
|
||||||
|
// In addition to setting the variable itself, we also need to
|
||||||
|
// set the render_target_array_index with it on output. We have to
|
||||||
|
// offset this by the base view index, because Metal isn't in on
|
||||||
|
// our little game here.
|
||||||
|
entry_func.fixup_hooks_out.push_back([=]() {
|
||||||
|
statement(to_expression(builtin_layer_id), " = ", to_expression(var_id), " - ",
|
||||||
|
to_expression(view_mask_buffer_id), "[0];");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -7883,6 +7994,12 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin)
|
|||||||
case BuiltInSamplePosition:
|
case BuiltInSamplePosition:
|
||||||
// Shouldn't be reached.
|
// Shouldn't be reached.
|
||||||
SPIRV_CROSS_THROW("Sample position is retrieved by a function in MSL.");
|
SPIRV_CROSS_THROW("Sample position is retrieved by a function in MSL.");
|
||||||
|
case BuiltInViewIndex:
|
||||||
|
if (execution.model != ExecutionModelFragment)
|
||||||
|
SPIRV_CROSS_THROW("ViewIndex is handled specially outside fragment shaders.");
|
||||||
|
// The ViewIndex was implicitly used in the prior stages to set the render_target_array_index,
|
||||||
|
// so we can get it from there.
|
||||||
|
return "render_target_array_index";
|
||||||
|
|
||||||
// Fragment function out
|
// Fragment function out
|
||||||
case BuiltInFragDepth:
|
case BuiltInFragDepth:
|
||||||
@ -8050,6 +8167,8 @@ string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id)
|
|||||||
return "uint";
|
return "uint";
|
||||||
case BuiltInSamplePosition:
|
case BuiltInSamplePosition:
|
||||||
return "float2";
|
return "float2";
|
||||||
|
case BuiltInViewIndex:
|
||||||
|
return "uint";
|
||||||
|
|
||||||
// Fragment function out
|
// Fragment function out
|
||||||
case BuiltInFragDepth:
|
case BuiltInFragDepth:
|
||||||
@ -8634,6 +8753,7 @@ void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &exp
|
|||||||
case BuiltInPrimitiveId:
|
case BuiltInPrimitiveId:
|
||||||
case BuiltInSubgroupSize:
|
case BuiltInSubgroupSize:
|
||||||
case BuiltInSubgroupLocalInvocationId:
|
case BuiltInSubgroupLocalInvocationId:
|
||||||
|
case BuiltInViewIndex:
|
||||||
expected_type = SPIRType::UInt;
|
expected_type = SPIRType::UInt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -8676,6 +8796,7 @@ void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr
|
|||||||
case BuiltInViewportIndex:
|
case BuiltInViewportIndex:
|
||||||
case BuiltInFragStencilRefEXT:
|
case BuiltInFragStencilRefEXT:
|
||||||
case BuiltInPrimitiveId:
|
case BuiltInPrimitiveId:
|
||||||
|
case BuiltInViewIndex:
|
||||||
expected_type = SPIRType::UInt;
|
expected_type = SPIRType::UInt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -191,12 +191,14 @@ public:
|
|||||||
uint32_t shader_patch_output_buffer_index = 27;
|
uint32_t shader_patch_output_buffer_index = 27;
|
||||||
uint32_t shader_tess_factor_buffer_index = 26;
|
uint32_t shader_tess_factor_buffer_index = 26;
|
||||||
uint32_t buffer_size_buffer_index = 25;
|
uint32_t buffer_size_buffer_index = 25;
|
||||||
|
uint32_t view_mask_buffer_index = 24;
|
||||||
uint32_t shader_input_wg_index = 0;
|
uint32_t shader_input_wg_index = 0;
|
||||||
bool enable_point_size_builtin = true;
|
bool enable_point_size_builtin = true;
|
||||||
bool disable_rasterization = false;
|
bool disable_rasterization = false;
|
||||||
bool capture_output_to_buffer = false;
|
bool capture_output_to_buffer = false;
|
||||||
bool swizzle_texture_samples = false;
|
bool swizzle_texture_samples = false;
|
||||||
bool tess_domain_origin_lower_left = false;
|
bool tess_domain_origin_lower_left = false;
|
||||||
|
bool multiview = false;
|
||||||
|
|
||||||
// Enable use of MSL 2.0 indirect argument buffers.
|
// Enable use of MSL 2.0 indirect argument buffers.
|
||||||
// MSL 2.0 must also be enabled.
|
// MSL 2.0 must also be enabled.
|
||||||
@ -268,6 +270,13 @@ public:
|
|||||||
return !buffers_requiring_array_length.empty();
|
return !buffers_requiring_array_length.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provide feedback to calling API to allow it to pass a buffer
|
||||||
|
// containing the view mask for the current multiview subpass.
|
||||||
|
bool needs_view_mask_buffer() const
|
||||||
|
{
|
||||||
|
return msl_options.multiview;
|
||||||
|
}
|
||||||
|
|
||||||
// Provide feedback to calling API to allow it to pass an output
|
// Provide feedback to calling API to allow it to pass an output
|
||||||
// buffer if the shader needs it.
|
// buffer if the shader needs it.
|
||||||
bool needs_output_buffer() const
|
bool needs_output_buffer() const
|
||||||
@ -526,12 +535,15 @@ protected:
|
|||||||
uint32_t builtin_base_vertex_id = 0;
|
uint32_t builtin_base_vertex_id = 0;
|
||||||
uint32_t builtin_instance_idx_id = 0;
|
uint32_t builtin_instance_idx_id = 0;
|
||||||
uint32_t builtin_base_instance_id = 0;
|
uint32_t builtin_base_instance_id = 0;
|
||||||
|
uint32_t builtin_view_idx_id = 0;
|
||||||
|
uint32_t builtin_layer_id = 0;
|
||||||
uint32_t builtin_invocation_id_id = 0;
|
uint32_t builtin_invocation_id_id = 0;
|
||||||
uint32_t builtin_primitive_id_id = 0;
|
uint32_t builtin_primitive_id_id = 0;
|
||||||
uint32_t builtin_subgroup_invocation_id_id = 0;
|
uint32_t builtin_subgroup_invocation_id_id = 0;
|
||||||
uint32_t builtin_subgroup_size_id = 0;
|
uint32_t builtin_subgroup_size_id = 0;
|
||||||
uint32_t swizzle_buffer_id = 0;
|
uint32_t swizzle_buffer_id = 0;
|
||||||
uint32_t buffer_size_buffer_id = 0;
|
uint32_t buffer_size_buffer_id = 0;
|
||||||
|
uint32_t view_mask_buffer_id = 0;
|
||||||
|
|
||||||
void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
|
void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
|
||||||
void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override;
|
void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override;
|
||||||
|
@ -203,6 +203,8 @@ def cross_compile_msl(shader, spirv, opt, iterations, paths):
|
|||||||
msl_args.append('3')
|
msl_args.append('3')
|
||||||
if '.line.' in shader:
|
if '.line.' in shader:
|
||||||
msl_args.append('--emit-line-directives')
|
msl_args.append('--emit-line-directives')
|
||||||
|
if '.multiview.' in shader:
|
||||||
|
msl_args.append('--msl-multiview')
|
||||||
|
|
||||||
subprocess.check_call(msl_args)
|
subprocess.check_call(msl_args)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user