diff --git a/CMakeLists.txt b/CMakeLists.txt index 203ec58b..ccaedc90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,7 +332,7 @@ if (SPIRV_CROSS_STATIC) endif() set(spirv-cross-abi-major 0) -set(spirv-cross-abi-minor 53) +set(spirv-cross-abi-minor 54) set(spirv-cross-abi-patch 0) if (SPIRV_CROSS_SHARED) diff --git a/main.cpp b/main.cpp index 58c7d0eb..3605a54a 100644 --- a/main.cpp +++ b/main.cpp @@ -645,6 +645,7 @@ struct CLIArguments bool msl_pad_fragment_output = false; bool msl_domain_lower_left = false; bool msl_argument_buffers = false; + uint32_t msl_argument_buffers_tier = 0; // Tier 1 bool msl_texture_buffer_native = false; bool msl_framebuffer_fetch = false; bool msl_invariant_float_math = false; @@ -856,8 +857,11 @@ static void print_help_msl() "\t[--msl-pad-fragment-output]:\n\t\tAlways emit color outputs as 4-component variables.\n" "\t\tIn Metal, the fragment shader must emit at least as many components as the render target format.\n" "\t[--msl-domain-lower-left]:\n\t\tUse a lower-left tessellation domain.\n" - "\t[--msl-argument-buffers]:\n\t\tEmit Indirect Argument buffers instead of plain bindings.\n" + "\t[--msl-argument-buffers]:\n\t\tEmit Metal argument buffers instead of discrete resource bindings.\n" "\t\tRequires MSL 2.0 to be enabled.\n" + "\t[--msl-argument-buffers-tier]:\n\t\tWhen using Metal argument buffers, indicate the Metal argument buffer tier level supported by the Metal platform.\n" + "\t\tUses same values as Metal MTLArgumentBuffersTier enumeration (0 = Tier1, 1 = Tier2).\n" + "\t\tSetting this value also enables msl-argument-buffers.\n" "\t[--msl-texture-buffer-native]:\n\t\tEnable native support for texel buffers. Otherwise, it is emulated as a normal texture.\n" "\t[--msl-framebuffer-fetch]:\n\t\tImplement subpass inputs with frame buffer fetch.\n" "\t\tEmits [[color(N)]] inputs in fragment stage.\n" @@ -1190,6 +1194,7 @@ static string compile_iteration(const CLIArguments &args, std::vector msl_opts.pad_fragment_output_components = args.msl_pad_fragment_output; msl_opts.tess_domain_origin_lower_left = args.msl_domain_lower_left; msl_opts.argument_buffers = args.msl_argument_buffers; + msl_opts.argument_buffers_tier = static_cast(args.msl_argument_buffers_tier); msl_opts.texture_buffer_native = args.msl_texture_buffer_native; msl_opts.multiview = args.msl_multiview; msl_opts.multiview_layered_rendering = args.msl_multiview_layered_rendering; @@ -1621,6 +1626,10 @@ static int main_inner(int argc, char *argv[]) cbs.add("--msl-pad-fragment-output", [&args](CLIParser &) { args.msl_pad_fragment_output = true; }); cbs.add("--msl-domain-lower-left", [&args](CLIParser &) { args.msl_domain_lower_left = true; }); cbs.add("--msl-argument-buffers", [&args](CLIParser &) { args.msl_argument_buffers = true; }); + cbs.add("--msl-argument-buffer-tier", [&args](CLIParser &parser) { + args.msl_argument_buffers_tier = parser.next_uint(); + args.msl_argument_buffers = true; + }); cbs.add("--msl-discrete-descriptor-set", [&args](CLIParser &parser) { args.msl_discrete_descriptor_sets.push_back(parser.next_uint()); }); cbs.add("--msl-device-argument-buffer", diff --git a/spirv_cross_c.cpp b/spirv_cross_c.cpp index 125dfd25..72614d78 100644 --- a/spirv_cross_c.cpp +++ b/spirv_cross_c.cpp @@ -734,6 +734,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_MSL_CHECK_DISCARDED_FRAG_STORES: options->msl.check_discarded_frag_stores = value != 0; break; + + case SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS_TIER: + options->msl.argument_buffers_tier = static_cast(value); + break; #endif default: diff --git a/spirv_cross_c.h b/spirv_cross_c.h index eeb2238e..826e25a7 100644 --- a/spirv_cross_c.h +++ b/spirv_cross_c.h @@ -40,7 +40,7 @@ extern "C" { /* Bumped if ABI or API breaks backwards compatibility. */ #define SPVC_C_API_VERSION_MAJOR 0 /* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 53 +#define SPVC_C_API_VERSION_MINOR 54 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -723,6 +723,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_GLSL_ENABLE_ROW_MAJOR_LOAD_WORKAROUND = 83 | SPVC_COMPILER_OPTION_GLSL_BIT, + SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS_TIER = 84 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; diff --git a/spirv_msl.cpp b/spirv_msl.cpp index 6ccbee87..38d22891 100644 --- a/spirv_msl.cpp +++ b/spirv_msl.cpp @@ -11608,11 +11608,14 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ } } - // Very specifically, image load-store in argument buffers are disallowed on MSL on iOS. - if (msl_options.is_ios() && physical_type.basetype == SPIRType::Image && physical_type.image.sampled == 2) + // iOS Tier 1 argument buffers do not support writable images. + if (physical_type.basetype == SPIRType::Image && + physical_type.image.sampled == 2 && + msl_options.is_ios() && + msl_options.argument_buffers_tier <= Options::ArgumentBuffersTier::Tier1 && + !has_decoration(orig_id, DecorationNonWritable)) { - if (!has_decoration(orig_id, DecorationNonWritable)) - SPIRV_CROSS_THROW("Writable images are not allowed in argument buffers on iOS."); + SPIRV_CROSS_THROW("Writable images are not allowed on Tier1 argument buffers on iOS."); } // Array information is baked into these types. @@ -16953,13 +16956,14 @@ bool CompilerMSL::descriptor_set_is_argument_buffer(uint32_t desc_set) const bool CompilerMSL::is_supported_argument_buffer_type(const SPIRType &type) const { - // Very specifically, image load-store in argument buffers are disallowed on MSL on iOS. - // But we won't know when the argument buffer is encoded whether this image will have - // a NonWritable decoration. So just use discrete arguments for all storage images - // on iOS. - bool is_storage_image = type.basetype == SPIRType::Image && type.image.sampled == 2; - bool is_supported_type = !msl_options.is_ios() || !is_storage_image; - return !type_is_msl_framebuffer_fetch(type) && is_supported_type; + // iOS Tier 1 argument buffers do not support writable images. + // When the argument buffer is encoded, we don't know whether this image will have a + // NonWritable decoration, so just use discrete arguments for all storage images on iOS. + bool is_supported_type = !(type.basetype == SPIRType::Image && + type.image.sampled == 2 && + msl_options.is_ios() && + msl_options.argument_buffers_tier <= Options::ArgumentBuffersTier::Tier1); + return is_supported_type && !type_is_msl_framebuffer_fetch(type); } void CompilerMSL::analyze_argument_buffers() diff --git a/spirv_msl.hpp b/spirv_msl.hpp index 7cd34c73..737575d4 100644 --- a/spirv_msl.hpp +++ b/spirv_msl.hpp @@ -339,10 +339,25 @@ public: bool dispatch_base = false; bool texture_1D_as_2D = false; - // Enable use of MSL 2.0 indirect argument buffers. + // Enable use of Metal argument buffers. // MSL 2.0 must also be enabled. bool argument_buffers = false; + // Defines Metal argument buffer tier levels. + // Uses same values as Metal MTLArgumentBuffersTier enumeration. + enum class ArgumentBuffersTier + { + Tier1 = 0, + Tier2 = 1, + }; + + // When using Metal argument buffers, indicates the Metal argument buffer tier level supported by the Metal platform. + // Ignored when Options::argument_buffers is disabled. + // - Tier1 supports writable images on macOS, but not on iOS. + // - Tier2 supports writable images on macOS and iOS, and higher resource count limits. + // Tier capabilities based on recommendations from Apple engineering. + ArgumentBuffersTier argument_buffers_tier = ArgumentBuffersTier::Tier1; + // Ensures vertex and instance indices start at zero. This reflects the behavior of HLSL with SV_VertexID and SV_InstanceID. bool enable_base_index_zero = false;