CompilerMSL vertex entry point return void when rasterization disabled.

Add CompilerMSL::Options::disable_rasterization input/output API flag.
Disable rasterization via API flag or when writing to textures.
Disable rasterization when shader declares no output.
Add test shaders for vertex no output and write texture forcing void output.
This commit is contained in:
Bill Hollings 2018-07-26 00:50:33 -04:00
parent cc7679ee45
commit ac238b858b
8 changed files with 155 additions and 14 deletions

View File

@ -0,0 +1,20 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct _10
{
uint4 _m0[1024];
};
struct main0_in
{
uint4 m_19 [[attribute(0)]];
};
vertex void main0(main0_in in [[stage_in]], device _10& _12 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]])
{
_12._m0[gl_VertexIndex] = in.m_19;
}

View File

@ -0,0 +1,27 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
};
struct main0_in
{
float4 m_17 [[attribute(0)]];
};
vertex void main0(main0_in in [[stage_in]], texture1d<uint> _37 [[texture(0)]], texture1d<uint, access::write> _34 [[texture(1)]])
{
main0_out out = {};
out.gl_Position = in.m_17;
for (int _45 = 0; _45 < 128; )
{
_34.write(_37.read(uint(_45)), uint(_45));
_45++;
continue;
}
}

View File

@ -0,0 +1,20 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct _10
{
uint4 _m0[1024];
};
struct main0_in
{
uint4 m_19 [[attribute(0)]];
};
vertex void main0(main0_in in [[stage_in]], device _10& _12 [[buffer(0)]], uint gl_VertexIndex [[vertex_id]])
{
_12._m0[gl_VertexIndex] = in.m_19;
}

View File

@ -0,0 +1,25 @@
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
};
struct main0_in
{
float4 m_17 [[attribute(0)]];
};
vertex void main0(main0_in in [[stage_in]], texture1d<uint> _37 [[texture(0)]], texture1d<uint, access::write> _34 [[texture(1)]])
{
main0_out out = {};
out.gl_Position = in.m_17;
for (int _22 = 0; _22 < 128; _22++)
{
_34.write(_37.read(uint(_22)), uint(_22));
}
}

View File

@ -0,0 +1,14 @@
#version 450
layout(binding = 0, std430) writeonly buffer _10_12
{
uvec4 _m0[1024];
} _12;
layout(location = 0) in uvec4 _19;
void main()
{
_12._m0[gl_VertexIndex] = _19;
}

View File

@ -0,0 +1,16 @@
#version 450
layout(binding = 1, r32ui) uniform writeonly uimage1D _32;
layout(binding = 0, r32ui) uniform readonly uimage1D _35;
layout(location = 0) in vec4 _14;
void main()
{
gl_Position = _14;
for (int _19 = 0; _19 < 128; _19++)
{
imageStore(_32, _19, imageLoad(_35, _19));
}
}

View File

@ -299,6 +299,11 @@ string CompilerMSL::compile()
stage_in_var_id = add_interface_block(StorageClassInput);
stage_uniforms_var_id = add_interface_block(StorageClassUniformConstant);
// Metal vertex functions that define no output must disable rasterization and return void.
// Provide feedback to calling API to allow runtime to disable pipeline rasterization.
if (!stage_out_var_id && (get_entry_point().model == ExecutionModelVertex))
msl_options.disable_rasterization = true;
// Convert the use of global variables to recursively-passed function parameters
localize_global_variables();
extract_global_variables_from_functions();
@ -376,6 +381,11 @@ void CompilerMSL::preprocess_op_codes()
add_header_line("#include <metal_atomic>");
add_pragma_line("#pragma clang diagnostic ignored \"-Wunused-variable\"");
}
// Metal vertex functions that write to textures must disable rasterization and return void.
// Provide feedback to calling API to allow runtime to disable pipeline rasterization.
if (preproc.uses_image_write && get_entry_point().model == ExecutionModelVertex)
msl_options.disable_rasterization = true;
}
// Move the Private and Workgroup global variables to the entry function.
@ -634,8 +644,7 @@ void CompilerMSL::mark_as_packable(SPIRType &type)
void CompilerMSL::mark_location_as_used_by_shader(uint32_t location, StorageClass storage)
{
MSLVertexAttr *p_va;
auto &execution = get_entry_point();
if ((execution.model == ExecutionModelVertex) && (storage == StorageClassInput) &&
if ((get_entry_point().model == ExecutionModelVertex) && (storage == StorageClassInput) &&
(p_va = vtx_attrs_by_location[location]))
p_va->used_by_shader = true;
}
@ -690,16 +699,20 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage)
{
ib_var_ref = stage_out_var_name;
// Add the output interface struct as a local variable to the entry function, force
// the entry function to return the output interface struct from any blocks that perform
// a function return, and indicate the output var requires early initialization
// Add the output interface struct as a local variable to the entry function.
// If the entry point should return the output struct, set the entry function
// to return the output interface struct, otherwise to return nothing.
// Indicate the output var requires early initialization.
bool ep_should_return_output =
!((get_entry_point().model == ExecutionModelVertex) && msl_options.disable_rasterization);
uint32_t rtn_id = ep_should_return_output ? ib_var_id : 0;
auto &entry_func = get<SPIRFunction>(entry_point);
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 = ib_var_id;
blk.return_value = rtn_id;
}
vars_needing_early_declaration.push_back(ib_var_id);
break;
@ -1741,7 +1754,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction)
break;
case OpAtomicXor:
MSL_AFMO (xor);
MSL_AFMO(xor);
break;
// Images
@ -2844,9 +2857,7 @@ string CompilerMSL::convert_row_major_matrix(string exp_str, const SPIRType &exp
// Called automatically at the end of the entry point function
void CompilerMSL::emit_fixup()
{
auto &execution = get_entry_point();
if ((execution.model == ExecutionModelVertex) && stage_out_var_id && !qual_pos_var_name.empty())
if ((get_entry_point().model == ExecutionModelVertex) && stage_out_var_id && !qual_pos_var_name.empty())
{
if (options.vertex.fixup_clipspace)
statement(qual_pos_var_name, ".z = (", qual_pos_var_name, ".z + ", qual_pos_var_name,
@ -3081,14 +3092,15 @@ string CompilerMSL::constant_expression(const SPIRConstant &c)
// entry type if the current function is the entry point function
string CompilerMSL::func_type_decl(SPIRType &type)
{
auto &execution = get_entry_point();
// The regular function return type. If not processing the entry point function, that's all we need
string return_type = type_to_glsl(type) + type_to_array_glsl(type);
if (!processing_entry_point)
return return_type;
// If an outgoing interface block has been defined, override the entry point return type
if (stage_out_var_id)
// 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_entry_point().model == ExecutionModelVertex) && msl_options.disable_rasterization);
if (stage_out_var_id && ep_should_return_output)
{
auto &so_var = get<SPIRVariable>(stage_out_var_id);
auto &so_type = get<SPIRType>(so_var.basetype);
@ -3097,6 +3109,7 @@ string CompilerMSL::func_type_decl(SPIRType &type)
// Prepend a entry type, based on the execution model
string entry_type;
auto &execution = get_entry_point();
switch (execution.model)
{
case ExecutionModelVertex:
@ -3609,7 +3622,7 @@ std::string CompilerMSL::sampler_type(const SPIRType &type)
return "sampler";
}
// Returns an MSL string describing the SPIR-V image type
// Returns an MSL string describing the SPIR-V image type
string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
{
auto *var = maybe_get<SPIRVariable>(id);
@ -4027,6 +4040,10 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui
suppress_missing_prototypes = true;
break;
case OpImageWrite:
uses_image_write = true;
break;
case OpAtomicExchange:
case OpAtomicCompareExchange:
case OpAtomicCompareExchangeWeak:

View File

@ -153,6 +153,7 @@ public:
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
bool enable_point_size_builtin = true;
bool disable_rasterization = false; // Used as both input and output
bool resolve_specialized_array_lengths = true;
bool is_ios()
@ -399,6 +400,7 @@ protected:
std::unordered_map<uint32_t, uint32_t> result_types;
bool suppress_missing_prototypes = false;
bool uses_atomics = false;
bool uses_image_write = false;
};
// Sorts the members of a SPIRType and associated Meta info based on a settable sorting