Merge pull request #848 from cdavis5e/capture-output-buffer

MSL: Add a setting to capture vertex shader output to a buffer.
This commit is contained in:
Hans-Kristian Arntzen 2019-02-07 15:11:41 +01:00 committed by GitHub
commit d9ed3dcc7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 372 additions and 35 deletions

View File

@ -490,6 +490,7 @@ struct CLIArguments
bool yflip = false;
bool sso = false;
bool support_nonzero_baseinstance = true;
bool msl_capture_output_to_buffer = false;
bool msl_swizzle_texture_samples = false;
bool msl_ios = false;
bool msl_pad_fragment_output = false;
@ -545,6 +546,7 @@ static void print_help()
"\t[--cpp-interface-name <name>]\n"
"\t[--msl]\n"
"\t[--msl-version <MMmmpp>]\n"
"\t[--msl-capture-output]\n"
"\t[--msl-swizzle-texture-samples]\n"
"\t[--msl-ios]\n"
"\t[--msl-pad-fragment-output]\n"
@ -714,6 +716,7 @@ static int main_inner(int argc, char *argv[])
cbs.add("--vulkan-semantics", [&args](CLIParser &) { args.vulkan_semantics = true; });
cbs.add("--flatten-multidimensional-arrays", [&args](CLIParser &) { args.flatten_multidimensional_arrays = true; });
cbs.add("--no-420pack-extension", [&args](CLIParser &) { args.use_420pack_extension = false; });
cbs.add("--msl-capture-output", [&args](CLIParser &) { args.msl_capture_output_to_buffer = true; });
cbs.add("--msl-swizzle-texture-samples", [&args](CLIParser &) { args.msl_swizzle_texture_samples = true; });
cbs.add("--msl-ios", [&args](CLIParser &) { args.msl_ios = true; });
cbs.add("--msl-pad-fragment-output", [&args](CLIParser &) { args.msl_pad_fragment_output = true; });
@ -843,6 +846,7 @@ static int main_inner(int argc, char *argv[])
auto msl_opts = msl_comp->get_msl_options();
if (args.set_msl_version)
msl_opts.msl_version = args.msl_version;
msl_opts.capture_output_to_buffer = args.msl_capture_output_to_buffer;
msl_opts.swizzle_texture_samples = args.msl_swizzle_texture_samples;
if (args.msl_ios)
msl_opts.platform = CompilerMSL::Options::iOS;

View File

@ -130,7 +130,7 @@ inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p
return t.gather_compare(s, spvForward<Ts>(params)...);
}
kernel void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture2d<float> foo [[texture(0)]], texture2d<float, access::write> bar [[texture(1)]], sampler fooSmplr [[sampler(0)]])
kernel void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture2d<float> foo [[texture(0)]], texture2d<float, access::write> bar [[texture(1)]], sampler fooSmplr [[sampler(0)]])
{
constant uint32_t& fooSwzl = spvAuxBuffer.swizzleConst[0];
bar.write(spvTextureSwizzle(foo.sample(fooSmplr, float2(1.0), level(0.0)), fooSwzl), uint2(int2(0)));

View File

@ -0,0 +1,29 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct UBO
{
float4x4 uMVP;
};
struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
};
struct main0_in
{
float4 aVertex [[attribute(0)]];
float3 aNormal [[attribute(1)]];
};
vertex void main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]], uint gl_BaseVertex [[base_vertex]], uint gl_InstanceIndex [[instance_id]], uint gl_BaseInstance [[base_instance]], device main0_out* spvOut [[buffer(28)]], device uint* spvIndirectParams [[buffer(29)]])
{
device main0_out& out = spvOut[(gl_InstanceIndex - gl_BaseInstance) * spvIndirectParams[0] + gl_VertexIndex - gl_BaseVertex];
out.gl_Position = _16.uMVP * in.aVertex;
out.vNormal = in.aNormal;
}

View File

@ -0,0 +1,29 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct UBO
{
float4x4 uMVP;
};
struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
};
struct main0_in
{
float4 aVertex [[attribute(0)]];
float3 aNormal [[attribute(1)]];
};
vertex void main0(main0_in in [[stage_in]], constant UBO& _18 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]], uint gl_BaseVertex [[base_vertex]], uint gl_InstanceIndex [[instance_id]], uint gl_BaseInstance [[base_instance]], device main0_out* spvOut [[buffer(28)]], device uint* spvIndirectParams [[buffer(29)]])
{
device main0_out& out = spvOut[(gl_InstanceIndex - gl_BaseInstance) * spvIndirectParams[0] + gl_VertexIndex - gl_BaseVertex];
out.gl_Position = _18.uMVP * in.aVertex;
out.vNormal = in.aNormal;
}

View File

@ -136,7 +136,7 @@ inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p
return t.gather_compare(s, spvForward<Ts>(params)...);
}
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSamp [[sampler(0)]], sampler tex2dSamp [[sampler(1)]], sampler tex3dSamp [[sampler(2)]], sampler texCubeSamp [[sampler(3)]], sampler tex2dArraySamp [[sampler(4)]], sampler texCubeArraySamp [[sampler(5)]], sampler depth2dSamp [[sampler(7)]], sampler depthCubeSamp [[sampler(8)]], sampler depth2dArraySamp [[sampler(9)]], sampler depthCubeArraySamp [[sampler(10)]])
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSamp [[sampler(0)]], sampler tex2dSamp [[sampler(1)]], sampler tex3dSamp [[sampler(2)]], sampler texCubeSamp [[sampler(3)]], sampler tex2dArraySamp [[sampler(4)]], sampler texCubeArraySamp [[sampler(5)]], sampler depth2dSamp [[sampler(7)]], sampler depthCubeSamp [[sampler(8)]], sampler depth2dArraySamp [[sampler(9)]], sampler depthCubeArraySamp [[sampler(10)]])
{
constant uint32_t& tex1dSwzl = spvAuxBuffer.swizzleConst[0];
constant uint32_t& tex2dSwzl = spvAuxBuffer.swizzleConst[1];

View File

@ -136,7 +136,7 @@ inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p
return t.gather_compare(s, spvForward<Ts>(params)...);
}
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture1d<int> tex1d [[texture(0)]], texture2d<int> tex2d [[texture(1)]], texture3d<int> tex3d [[texture(2)]], texturecube<int> texCube [[texture(3)]], texture2d_array<int> tex2dArray [[texture(4)]], texturecube_array<int> texCubeArray [[texture(5)]], texture2d<int> texBuffer [[texture(6)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]])
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture1d<int> tex1d [[texture(0)]], texture2d<int> tex2d [[texture(1)]], texture3d<int> tex3d [[texture(2)]], texturecube<int> texCube [[texture(3)]], texture2d_array<int> tex2dArray [[texture(4)]], texturecube_array<int> texCubeArray [[texture(5)]], texture2d<int> texBuffer [[texture(6)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]])
{
constant uint32_t& tex1dSwzl = spvAuxBuffer.swizzleConst[0];
constant uint32_t& tex2dSwzl = spvAuxBuffer.swizzleConst[1];

View File

@ -183,7 +183,7 @@ float4 doSwizzle(thread texture1d<float> tex1d, thread const sampler tex1dSmplr,
return c;
}
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(7)]], sampler depthCubeSmplr [[sampler(8)]], sampler depth2dArraySmplr [[sampler(9)]], sampler depthCubeArraySmplr [[sampler(10)]])
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(7)]], sampler depthCubeSmplr [[sampler(8)]], sampler depth2dArraySmplr [[sampler(9)]], sampler depthCubeArraySmplr [[sampler(10)]])
{
constant uint32_t& tex1dSwzl = spvAuxBuffer.swizzleConst[0];
constant uint32_t& tex2dSwzl = spvAuxBuffer.swizzleConst[1];

View File

@ -136,7 +136,7 @@ inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p
return t.gather_compare(s, spvForward<Ts>(params)...);
}
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture1d<uint> tex1d [[texture(0)]], texture2d<uint> tex2d [[texture(1)]], texture3d<uint> tex3d [[texture(2)]], texturecube<uint> texCube [[texture(3)]], texture2d_array<uint> tex2dArray [[texture(4)]], texturecube_array<uint> texCubeArray [[texture(5)]], texture2d<uint> texBuffer [[texture(6)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]])
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture1d<uint> tex1d [[texture(0)]], texture2d<uint> tex2d [[texture(1)]], texture3d<uint> tex3d [[texture(2)]], texturecube<uint> texCube [[texture(3)]], texture2d_array<uint> tex2dArray [[texture(4)]], texturecube_array<uint> texCubeArray [[texture(5)]], texture2d<uint> texBuffer [[texture(6)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]])
{
constant uint32_t& tex1dSwzl = spvAuxBuffer.swizzleConst[0];
constant uint32_t& tex2dSwzl = spvAuxBuffer.swizzleConst[1];

View File

@ -136,7 +136,7 @@ inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p
return t.gather_compare(s, spvForward<Ts>(params)...);
}
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(7)]], sampler depthCubeSmplr [[sampler(8)]], sampler depth2dArraySmplr [[sampler(9)]], sampler depthCubeArraySmplr [[sampler(10)]])
fragment void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex2dSmplr [[sampler(1)]], sampler tex3dSmplr [[sampler(2)]], sampler texCubeSmplr [[sampler(3)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(7)]], sampler depthCubeSmplr [[sampler(8)]], sampler depth2dArraySmplr [[sampler(9)]], sampler depthCubeArraySmplr [[sampler(10)]])
{
constant uint32_t& tex1dSwzl = spvAuxBuffer.swizzleConst[0];
constant uint32_t& tex2dSwzl = spvAuxBuffer.swizzleConst[1];

View File

@ -188,7 +188,7 @@ float4 do_samples(thread const texture1d<float> t1, thread const sampler t1Smplr
return c;
}
fragment main0_out main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex3dSmplr [[sampler(2)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(7)]], sampler depthCubeSmplr [[sampler(8)]], sampler depthCubeArraySmplr [[sampler(10)]], sampler defaultSampler [[sampler(11)]], sampler shadowSampler [[sampler(12)]])
fragment main0_out main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture1d<float> tex1d [[texture(0)]], texture2d<float> tex2d [[texture(1)]], texture3d<float> tex3d [[texture(2)]], texturecube<float> texCube [[texture(3)]], texture2d_array<float> tex2dArray [[texture(4)]], texturecube_array<float> texCubeArray [[texture(5)]], texture2d<float> texBuffer [[texture(6)]], depth2d<float> depth2d [[texture(7)]], depthcube<float> depthCube [[texture(8)]], depth2d_array<float> depth2dArray [[texture(9)]], depthcube_array<float> depthCubeArray [[texture(10)]], sampler tex1dSmplr [[sampler(0)]], sampler tex3dSmplr [[sampler(2)]], sampler tex2dArraySmplr [[sampler(4)]], sampler texCubeArraySmplr [[sampler(5)]], sampler depth2dSmplr [[sampler(7)]], sampler depthCubeSmplr [[sampler(8)]], sampler depthCubeArraySmplr [[sampler(10)]], sampler defaultSampler [[sampler(11)]], sampler shadowSampler [[sampler(12)]])
{
main0_out out = {};
constant uint32_t& tex1dSwzl = spvAuxBuffer.swizzleConst[0];

View File

@ -130,7 +130,7 @@ inline vec<T, 4> spvGatherCompareSwizzle(sampler s, const thread Tex& t, Ts... p
return t.gather_compare(s, spvForward<Ts>(params)...);
}
kernel void main0(constant spvAux& spvAuxBuffer [[buffer(0)]], texture2d<float> foo [[texture(0)]], texture2d<float, access::write> bar [[texture(1)]], sampler fooSmplr [[sampler(0)]])
kernel void main0(constant spvAux& spvAuxBuffer [[buffer(30)]], texture2d<float> foo [[texture(0)]], texture2d<float, access::write> bar [[texture(1)]], sampler fooSmplr [[sampler(0)]])
{
constant uint32_t& fooSwzl = spvAuxBuffer.swizzleConst[0];
float4 a = spvTextureSwizzle(foo.sample(fooSmplr, float2(1.0), level(0.0)), fooSwzl);

View File

@ -0,0 +1,29 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct UBO
{
float4x4 uMVP;
};
struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
};
struct main0_in
{
float4 aVertex [[attribute(0)]];
float3 aNormal [[attribute(1)]];
};
vertex void main0(main0_in in [[stage_in]], constant UBO& _16 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]], uint gl_BaseVertex [[base_vertex]], uint gl_InstanceIndex [[instance_id]], uint gl_BaseInstance [[base_instance]], device main0_out* spvOut [[buffer(28)]], device uint* spvIndirectParams [[buffer(29)]])
{
device main0_out& out = spvOut[(gl_InstanceIndex - gl_BaseInstance) * spvIndirectParams[0] + gl_VertexIndex - gl_BaseVertex];
out.gl_Position = _16.uMVP * in.aVertex;
out.vNormal = in.aNormal;
}

View File

@ -0,0 +1,36 @@
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct UBO
{
float4x4 uMVP;
};
struct main0_out
{
float3 vNormal [[user(locn0)]];
float4 gl_Position [[position]];
};
struct main0_in
{
float4 aVertex [[attribute(0)]];
float3 aNormal [[attribute(1)]];
};
void set_output(device float4& gl_Position, constant UBO& v_18, thread float4& aVertex, device float3& vNormal, thread float3& aNormal)
{
gl_Position = v_18.uMVP * aVertex;
vNormal = aNormal;
}
vertex void main0(main0_in in [[stage_in]], constant UBO& v_18 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]], uint gl_BaseVertex [[base_vertex]], uint gl_InstanceIndex [[instance_id]], uint gl_BaseInstance [[base_instance]], device main0_out* spvOut [[buffer(28)]], device uint* spvIndirectParams [[buffer(29)]])
{
device main0_out& out = spvOut[(gl_InstanceIndex - gl_BaseInstance) * spvIndirectParams[0] + gl_VertexIndex - gl_BaseVertex];
set_output(out.gl_Position, v_18, in.aVertex, out.vNormal, in.aNormal);
}

View File

@ -0,0 +1,17 @@
#version 310 es
layout(std140) uniform UBO
{
uniform mat4 uMVP;
};
layout(location = 0) in vec4 aVertex;
layout(location = 1) in vec3 aNormal;
layout(location = 0) out vec3 vNormal;
void main()
{
gl_Position = uMVP * aVertex;
vNormal = aNormal;
}

View File

@ -0,0 +1,22 @@
#version 310 es
layout(std140) uniform UBO
{
uniform mat4 uMVP;
};
layout(location = 0) in vec4 aVertex;
layout(location = 1) in vec3 aNormal;
layout(location = 0) out vec3 vNormal;
void set_output()
{
gl_Position = uMVP * aVertex;
vNormal = aNormal;
}
void main()
{
set_output();
}

View File

@ -90,25 +90,55 @@ void CompilerMSL::set_fragment_output_components(uint32_t location, uint32_t com
void CompilerMSL::build_implicit_builtins()
{
bool need_sample_pos = active_input_builtins.get(BuiltInSamplePosition);
if (need_subpass_input || need_sample_pos)
if (need_subpass_input || need_sample_pos || capture_output_to_buffer)
{
bool has_frag_coord = false;
bool has_sample_id = false;
bool has_vertex_idx = false;
bool has_base_vertex = false;
bool has_instance_idx = false;
bool has_base_instance = false;
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
if (need_subpass_input && var.storage == StorageClassInput && ir.meta[var.self].decoration.builtin &&
ir.meta[var.self].decoration.builtin_type == BuiltInFragCoord)
if (var.storage != StorageClassInput || !ir.meta[var.self].decoration.builtin)
return;
if (need_subpass_input && ir.meta[var.self].decoration.builtin_type == BuiltInFragCoord)
{
builtin_frag_coord_id = var.self;
has_frag_coord = true;
}
if (need_sample_pos && var.storage == StorageClassInput && ir.meta[var.self].decoration.builtin &&
ir.meta[var.self].decoration.builtin_type == BuiltInSampleId)
if (need_sample_pos && ir.meta[var.self].decoration.builtin_type == BuiltInSampleId)
{
builtin_sample_id_id = var.self;
has_sample_id = true;
}
if (capture_output_to_buffer)
{
switch (ir.meta[var.self].decoration.builtin_type)
{
case BuiltInVertexIndex:
builtin_vertex_idx_id = var.self;
has_vertex_idx = true;
break;
case BuiltInBaseVertex:
builtin_base_vertex_id = var.self;
has_base_vertex = true;
break;
case BuiltInInstanceIndex:
builtin_instance_idx_id = var.self;
has_instance_idx = true;
break;
case BuiltInBaseInstance:
builtin_base_instance_id = var.self;
has_base_instance = true;
break;
default:
break;
}
}
});
if (!has_frag_coord && need_subpass_input)
@ -163,9 +193,67 @@ void CompilerMSL::build_implicit_builtins()
set_decoration(var_id, DecorationBuiltIn, BuiltInSampleId);
builtin_sample_id_id = var_id;
}
if (capture_output_to_buffer &&
(!has_vertex_idx || !has_base_vertex || !has_instance_idx || !has_base_instance))
{
uint32_t offset = ir.increase_bound_by(2);
uint32_t type_id = offset;
uint32_t type_ptr_id = offset + 1;
SPIRType uint_type;
uint_type.basetype = SPIRType::UInt;
uint_type.width = 32;
set<SPIRType>(type_id, uint_type);
SPIRType uint_type_ptr;
uint_type_ptr = uint_type;
uint_type_ptr.pointer = true;
uint_type_ptr.parent_type = type_id;
uint_type_ptr.storage = StorageClassInput;
auto &ptr_type = set<SPIRType>(type_ptr_id, uint_type_ptr);
ptr_type.self = type_id;
if (!has_vertex_idx)
{
uint32_t var_id = ir.increase_bound_by(1);
// Create gl_VertexIndex.
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
set_decoration(var_id, DecorationBuiltIn, BuiltInVertexIndex);
builtin_vertex_idx_id = var_id;
}
if (!has_base_vertex)
{
uint32_t var_id = ir.increase_bound_by(1);
// Create gl_BaseVertex.
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
set_decoration(var_id, DecorationBuiltIn, BuiltInBaseVertex);
builtin_base_vertex_id = var_id;
}
if (!has_instance_idx)
{
uint32_t var_id = ir.increase_bound_by(1);
// Create gl_InstanceIndex.
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
set_decoration(var_id, DecorationBuiltIn, BuiltInInstanceIndex);
builtin_instance_idx_id = var_id;
}
if (!has_base_instance)
{
uint32_t var_id = ir.increase_bound_by(1);
// Create gl_BaseInstance.
set<SPIRVariable>(var_id, type_ptr_id, StorageClassInput);
set_decoration(var_id, DecorationBuiltIn, BuiltInBaseInstance);
builtin_base_instance_id = var_id;
}
}
}
if (msl_options.swizzle_texture_samples && has_sampled_images)
if (needs_aux_buffer_def)
{
uint32_t offset = ir.increase_bound_by(5);
uint32_t type_id = offset;
@ -174,7 +262,7 @@ void CompilerMSL::build_implicit_builtins()
uint32_t struct_ptr_id = offset + 3;
uint32_t var_id = offset + 4;
// Create a buffer to hold the swizzle constants.
// Create a buffer to hold extra data, including the swizzle constants.
SPIRType uint_type;
uint_type.basetype = SPIRType::UInt;
uint_type.width = 32;
@ -194,8 +282,8 @@ void CompilerMSL::build_implicit_builtins()
type.self = struct_id;
set_decoration(struct_id, DecorationBlock);
set_name(struct_id, "spvAux");
set_member_name(struct_id, 0, "swizzleConst");
set_member_decoration(struct_id, 0, DecorationOffset, 0);
set_member_name(struct_id, k_aux_mbr_idx_swizzle_const, "swizzleConst");
set_member_decoration(struct_id, k_aux_mbr_idx_swizzle_const, DecorationOffset, 0);
SPIRType struct_type_ptr = struct_type;
struct_type_ptr.pointer = true;
@ -232,6 +320,12 @@ static string create_sampler_address(const char *prefix, MSLSamplerAddress addr)
}
}
SPIRType &CompilerMSL::get_stage_out_struct_type()
{
auto &so_var = get<SPIRVariable>(stage_out_var_id);
return get_variable_data_type(so_var);
}
void CompilerMSL::emit_entry_point_declarations()
{
// FIXME: Get test coverage here ...
@ -409,7 +503,8 @@ string CompilerMSL::compile()
backend.allow_truncated_access_chain = true;
backend.array_is_value_type = false;
is_rasterization_disabled = msl_options.disable_rasterization;
capture_output_to_buffer = msl_options.capture_output_to_buffer;
is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer;
replace_illegal_names();
@ -1392,14 +1487,35 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
bool ep_should_return_output = !get_is_rasterization_disabled();
uint32_t rtn_id = ep_should_return_output ? ib_var_id : 0;
auto &entry_func = get<SPIRFunction>(ir.default_entry_point);
entry_func.add_local_variable(ib_var_id);
for (auto &blk_id : entry_func.blocks)
if (!capture_output_to_buffer)
{
auto &blk = get<SPIRBlock>(blk_id);
if (blk.terminator == SPIRBlock::Return)
blk.return_value = rtn_id;
entry_func.add_local_variable(ib_var_id);
for (auto &blk_id : entry_func.blocks)
{
auto &blk = get<SPIRBlock>(blk_id);
if (blk.terminator == SPIRBlock::Return)
blk.return_value = rtn_id;
}
vars_needing_early_declaration.push_back(ib_var_id);
}
else
{
// Instead of declaring a struct variable to hold the output and then
// copying that to the output buffer, we'll declare the output variable
// as a reference to the final output element in the buffer. Then we can
// avoid the extra copy.
entry_func.fixup_hooks_in.push_back([=]() {
if (stage_out_var_id)
{
// The first member of the indirect buffer is always the number of vertices
// to draw.
statement("device ", to_name(ir.default_entry_point), "_", ib_var_ref, "& ", ib_var_ref, " = ",
output_buffer_var_name, "[(", to_expression(builtin_instance_idx_id), " - ",
to_expression(builtin_base_instance_id), ") * spvIndirectParams[0] + ",
to_expression(builtin_vertex_idx_id), " - ", to_expression(builtin_base_vertex_id), "];");
}
});
}
vars_needing_early_declaration.push_back(ib_var_id);
break;
}
@ -4069,9 +4185,9 @@ void CompilerMSL::emit_fixup()
}
}
// Emit a structure member, padding and packing to maintain the correct memeber alignments.
void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const string &qualifier, uint32_t)
// Return a string defining a structure member, with padding and packing.
string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const string &qualifier)
{
auto &membertype = get<SPIRType>(member_type_id);
@ -4116,8 +4232,15 @@ void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_
pack_pfx = "packed_";
}
statement(pack_pfx, type_to_glsl(*effective_membertype), " ", qualifier, to_member_name(type, index),
member_attribute_qualifier(type, index), type_to_array_glsl(*effective_membertype), ";");
return join(pack_pfx, type_to_glsl(*effective_membertype), " ", qualifier, to_member_name(type, index),
member_attribute_qualifier(type, index), type_to_array_glsl(membertype), ";");
}
// Emit a structure member, padding and packing to maintain the correct memeber alignments.
void CompilerMSL::emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const string &qualifier, uint32_t)
{
statement(to_struct_member(type, member_type_id, index, qualifier));
}
// Return a MSL qualifier for the specified function attribute member
@ -4354,11 +4477,7 @@ string CompilerMSL::func_type_decl(SPIRType &type)
// If an outgoing interface block has been defined, and it should be returned, override the entry point return type
bool ep_should_return_output = !get_is_rasterization_disabled();
if (stage_out_var_id && ep_should_return_output)
{
auto &so_var = get<SPIRVariable>(stage_out_var_id);
auto &so_type = get_variable_data_type(so_var);
return_type = type_to_glsl(so_type) + type_to_array_glsl(type);
}
return_type = type_to_glsl(get_stage_out_struct_type()) + type_to_array_glsl(type);
// Prepend a entry type, based on the execution model
string entry_type;
@ -4421,6 +4540,11 @@ string CompilerMSL::get_argument_address_space(const SPIRVariable &argument)
// No address space for plain values.
return type.pointer ? "thread" : "";
case StorageClassOutput:
if (capture_output_to_buffer)
return "device";
break;
default:
break;
}
@ -4458,6 +4582,11 @@ string CompilerMSL::get_type_address_space(const SPIRType &type)
// No address space for plain values.
return type.pointer ? "thread" : "";
case StorageClassOutput:
if (capture_output_to_buffer)
return "device";
break;
default:
break;
}
@ -4623,6 +4752,21 @@ string CompilerMSL::entry_point_args(bool append_comma)
if (needs_instance_idx_arg)
ep_args += built_in_func_arg(BuiltInInstanceIndex, !ep_args.empty());
if (capture_output_to_buffer)
{
// Add parameters to hold the indirect draw parameters and the shader output. This has to be handled
// specially because it needs to be a pointer, not a reference.
if (stage_out_var_id)
{
if (!ep_args.empty())
ep_args += ", ";
ep_args += join("device ", type_to_glsl(get_stage_out_struct_type()), "* ", output_buffer_var_name,
" [[buffer(", msl_options.shader_output_buffer_index, ")]], ");
ep_args +=
join("device uint* spvIndirectParams [[buffer(", msl_options.indirect_params_buffer_index, ")]]");
}
}
if (!ep_args.empty() && append_comma)
ep_args += ", ";
@ -5837,6 +5981,7 @@ bool CompilerMSL::SampledImageScanner::handle(spv::Op opcode, const uint32_t *ar
case OpImageDrefGather:
compiler.has_sampled_images =
compiler.has_sampled_images || compiler.is_sampled_image_type(compiler.expression_type(args[2]));
compiler.needs_aux_buffer_def = compiler.needs_aux_buffer_def || compiler.has_sampled_images;
break;
default:
break;

View File

@ -147,6 +147,10 @@ static const uint32_t kPushConstDescSet = ~(0u);
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstBinding = 0;
// The current version of the aux buffer structure. It must be incremented any time a
// new field is added to the aux buffer.
#define SPIRV_CROSS_MSL_AUX_BUFFER_STRUCT_VERSION 1
// Decompiles SPIR-V to Metal Shading Language
class CompilerMSL : public CompilerGLSL
{
@ -163,9 +167,12 @@ public:
Platform platform = macOS;
uint32_t msl_version = make_msl_version(1, 2);
uint32_t texel_buffer_texture_width = 4096; // Width of 2D Metal textures used as 1D texel buffers
uint32_t aux_buffer_index = 0;
uint32_t aux_buffer_index = 30;
uint32_t indirect_params_buffer_index = 29;
uint32_t shader_output_buffer_index = 28;
bool enable_point_size_builtin = true;
bool disable_rasterization = false;
bool capture_output_to_buffer = false;
bool swizzle_texture_samples = false;
// Fragment output in MSL must have at least as many components as the render pass.
@ -234,6 +241,13 @@ public:
return used_aux_buffer;
}
// Provide feedback to calling API to allow it to pass an output
// buffer if the shader needs it.
bool needs_output_buffer() const
{
return capture_output_to_buffer && stage_out_var_id != 0;
}
// An enum of SPIR-V functions that are implemented in additional
// source code that is added to the shader if necessary.
enum SPVFuncImpl
@ -329,6 +343,8 @@ protected:
void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) override;
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
void emit_fixup() override;
std::string to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const std::string &qualifier = "");
void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index,
const std::string &qualifier = "", uint32_t base_offset = 0) override;
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
@ -415,6 +431,7 @@ protected:
MSLStructMemberKey get_struct_member_key(uint32_t type_id, uint32_t index);
std::string get_argument_address_space(const SPIRVariable &argument);
std::string get_type_address_space(const SPIRType &type);
SPIRType &get_stage_out_struct_type();
void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, uint32_t mem_order_1,
uint32_t mem_order_2, bool has_mem_order_2, uint32_t op0, uint32_t op1 = 0,
bool op1_is_pointer = false, bool op1_is_literal = false, uint32_t op2 = 0);
@ -427,6 +444,10 @@ protected:
void emit_entry_point_declarations() override;
uint32_t builtin_frag_coord_id = 0;
uint32_t builtin_sample_id_id = 0;
uint32_t builtin_vertex_idx_id = 0;
uint32_t builtin_base_vertex_id = 0;
uint32_t builtin_instance_idx_id = 0;
uint32_t builtin_base_instance_id = 0;
uint32_t aux_buffer_id = 0;
void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override;
@ -451,12 +472,15 @@ protected:
bool needs_vertex_idx_arg = false;
bool needs_instance_idx_arg = false;
bool is_rasterization_disabled = false;
bool capture_output_to_buffer = false;
bool needs_aux_buffer_def = false;
bool used_aux_buffer = false;
std::string qual_pos_var_name;
std::string stage_in_var_name = "in";
std::string stage_out_var_name = "out";
std::string sampler_name_suffix = "Smplr";
std::string swizzle_name_suffix = "Swzl";
std::string output_buffer_var_name = "spvOut";
spv::Op previous_instruction_opcode = spv::OpNop;
std::unordered_map<uint32_t, MSLConstexprSampler> constexpr_samplers;

View File

@ -154,6 +154,8 @@ def cross_compile_msl(shader, spirv, opt):
msl_args.append('--msl-ios')
if '.pad-fragment.' in shader:
msl_args.append('--msl-pad-fragment-output')
if '.capture.' in shader:
msl_args.append('--msl-capture-output')
subprocess.check_call(msl_args)