From 3a6349827530f8392cbf22b1dc528668d915eb78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=91=D1=80=D0=B0=D0=BD=D0=B8=D0=BC=D0=B8=D1=80=20=D0=9A?= =?UTF-8?q?=D0=B0=D1=80=D0=B0=D1=9F=D0=B8=D1=9B?= Date: Sat, 17 Oct 2020 22:52:04 -0700 Subject: [PATCH] Updated spirv-cross. --- 3rdparty/spirv-cross/main.cpp | 14 +++- 3rdparty/spirv-cross/spirv_cross_c.cpp | 44 ++++++++++ 3rdparty/spirv-cross/spirv_cross_c.h | 7 +- 3rdparty/spirv-cross/spirv_glsl.cpp | 29 +++---- 3rdparty/spirv-cross/spirv_glsl.hpp | 6 +- 3rdparty/spirv-cross/spirv_msl.cpp | 112 ++++++++++++++++++++++--- 3rdparty/spirv-cross/spirv_msl.hpp | 9 +- 7 files changed, 185 insertions(+), 36 deletions(-) diff --git a/3rdparty/spirv-cross/main.cpp b/3rdparty/spirv-cross/main.cpp index 6e6e94aac..f0660bea2 100644 --- a/3rdparty/spirv-cross/main.cpp +++ b/3rdparty/spirv-cross/main.cpp @@ -563,6 +563,8 @@ struct CLIArguments bool msl_vertex_for_tessellation = false; uint32_t msl_additional_fixed_sample_mask = 0xffffffff; bool msl_arrayed_subpass_input = false; + uint32_t msl_r32ui_linear_texture_alignment = 4; + uint32_t msl_r32ui_alignment_constant_id = 65535; bool glsl_emit_push_constant_as_ubo = false; bool glsl_emit_ubo_as_plain_uniforms = false; bool glsl_force_flattened_io_blocks = false; @@ -768,7 +770,11 @@ static void print_help_msl() "\t[--msl-additional-fixed-sample-mask ]:\n" "\t\tSet an additional fixed sample mask. If the shader outputs a sample mask, then the final sample mask will be a bitwise AND of the two.\n" "\t[--msl-arrayed-subpass-input]:\n\t\tAssume that images of dimension SubpassData have multiple layers. Layered input attachments are accessed relative to BuiltInLayer.\n" - "\t\tThis option has no effect if multiview is also enabled.\n"); + "\t\tThis option has no effect if multiview is also enabled.\n" + "\t[--msl-r32ui-linear-texture-align ]:\n\t\tThe required alignment of linear textures of format MTLPixelFormatR32Uint.\n" + "\t\tThis is used to align the row stride for atomic accesses to such images.\n" + "\t[--msl-r32ui-linear-texture-align-constant-id ]:\n\t\tThe function constant ID to use for the linear texture alignment.\n" + "\t\tOn MSL 1.2 or later, you can override the alignment by setting this function constant.\n"); // clang-format on } @@ -1007,6 +1013,8 @@ static string compile_iteration(const CLIArguments &args, std::vector msl_opts.vertex_for_tessellation = args.msl_vertex_for_tessellation; msl_opts.additional_fixed_sample_mask = args.msl_additional_fixed_sample_mask; msl_opts.arrayed_subpass_input = args.msl_arrayed_subpass_input; + msl_opts.r32ui_linear_texture_alignment = args.msl_r32ui_linear_texture_alignment; + msl_opts.r32ui_alignment_constant_id = args.msl_r32ui_alignment_constant_id; msl_comp->set_msl_options(msl_opts); for (auto &v : args.msl_discrete_descriptor_sets) msl_comp->add_discrete_descriptor_set(v); @@ -1427,6 +1435,10 @@ static int main_inner(int argc, char *argv[]) cbs.add("--msl-additional-fixed-sample-mask", [&args](CLIParser &parser) { args.msl_additional_fixed_sample_mask = parser.next_hex_uint(); }); cbs.add("--msl-arrayed-subpass-input", [&args](CLIParser &) { args.msl_arrayed_subpass_input = true; }); + cbs.add("--msl-r32ui-linear-texture-align", + [&args](CLIParser &parser) { args.msl_r32ui_linear_texture_alignment = parser.next_uint(); }); + cbs.add("--msl-r32ui-linear-texture-align-constant-id", + [&args](CLIParser &parser) { args.msl_r32ui_alignment_constant_id = parser.next_uint(); }); cbs.add("--extension", [&args](CLIParser &parser) { args.extensions.push_back(parser.next_string()); }); cbs.add("--rename-entry-point", [&args](CLIParser &parser) { auto old_name = parser.next_string(); diff --git a/3rdparty/spirv-cross/spirv_cross_c.cpp b/3rdparty/spirv-cross/spirv_cross_c.cpp index 25687f2c6..cbe3a5585 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.cpp +++ b/3rdparty/spirv-cross/spirv_cross_c.cpp @@ -666,6 +666,14 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c case SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT: options->msl.arrayed_subpass_input = value != 0; break; + + case SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT: + options->msl.r32ui_linear_texture_alignment = value; + break; + + case SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID: + options->msl.r32ui_alignment_constant_id = value; + break; #endif default: @@ -1239,6 +1247,42 @@ spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, SpvExecutio #endif } +spvc_result spvc_compiler_msl_set_combined_sampler_suffix(spvc_compiler compiler, const char *suffix) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; + } + + auto &msl = *static_cast(compiler->compiler.get()); + msl.set_combined_sampler_suffix(suffix); + return SPVC_SUCCESS; +#else + (void)suffix; + compiler->context->report_error("MSL function used on a non-MSL backend."); + return SPVC_ERROR_INVALID_ARGUMENT; +#endif +} + +const char *spvc_compiler_msl_get_combined_sampler_suffix(spvc_compiler compiler) +{ +#if SPIRV_CROSS_C_API_MSL + if (compiler->backend != SPVC_BACKEND_MSL) + { + compiler->context->report_error("MSL function used on a non-MSL backend."); + return ""; + } + + auto &msl = *static_cast(compiler->compiler.get()); + return msl.get_combined_sampler_suffix(); +#else + compiler->context->report_error("MSL function used on a non-MSL backend."); + return ""; +#endif +} + #if SPIRV_CROSS_C_API_MSL static void spvc_convert_msl_sampler(MSLConstexprSampler &samp, const spvc_msl_constexpr_sampler *sampler) { diff --git a/3rdparty/spirv-cross/spirv_cross_c.h b/3rdparty/spirv-cross/spirv_cross_c.h index 06d832ce8..f52abcda9 100644 --- a/3rdparty/spirv-cross/spirv_cross_c.h +++ b/3rdparty/spirv-cross/spirv_cross_c.h @@ -33,7 +33,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 39 +#define SPVC_C_API_VERSION_MINOR 41 /* Bumped if internal implementation details change. */ #define SPVC_C_API_VERSION_PATCH 0 @@ -638,6 +638,8 @@ typedef enum spvc_compiler_option SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING = 67 | SPVC_COMPILER_OPTION_MSL_BIT, SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT = 68 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT = 69 | SPVC_COMPILER_OPTION_MSL_BIT, + SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID = 70 | SPVC_COMPILER_OPTION_MSL_BIT, SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff } spvc_compiler_option; @@ -767,6 +769,9 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler c SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding); +SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_combined_sampler_suffix(spvc_compiler compiler, const char *suffix); +SPVC_PUBLIC_API const char *spvc_compiler_msl_get_combined_sampler_suffix(spvc_compiler compiler); + /* * Reflect resources. * Maps almost 1:1 to C++ API. diff --git a/3rdparty/spirv-cross/spirv_glsl.cpp b/3rdparty/spirv-cross/spirv_glsl.cpp index 130c28848..e5db12f3b 100644 --- a/3rdparty/spirv-cross/spirv_glsl.cpp +++ b/3rdparty/spirv-cross/spirv_glsl.cpp @@ -9313,8 +9313,8 @@ void CompilerGLSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_ex auto lhs = to_dereferenced_expression(lhs_expression); - // We might need to bitcast in order to store to a builtin. - bitcast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression)); + // We might need to cast in order to store to a builtin. + cast_to_builtin_store(lhs_expression, rhs, expression_type(rhs_expression)); // Tries to optimize assignments like " = op expr". // While this is purely cosmetic, this is important for legacy ESSL where loop @@ -9477,8 +9477,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (expr_type.vecsize > type.vecsize) expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0)); - // We might need to bitcast in order to load from a builtin. - bitcast_from_builtin_load(ptr, expr, type); + // We might need to cast in order to load from a builtin. + cast_from_builtin_load(ptr, expr, type); // We might be trying to load a gl_Position[N], where we should be // doing float4[](gl_in[i].gl_Position, ...) instead. @@ -12040,18 +12040,11 @@ bool CompilerGLSL::is_non_native_row_major_matrix(uint32_t id) if (backend.native_row_major_matrix && !is_legacy()) return false; - // Non-matrix or column-major matrix types do not need to be converted. - if (!has_decoration(id, DecorationRowMajor)) - return false; - - // Only square row-major matrices can be converted at this time. - // Converting non-square matrices will require defining custom GLSL function that - // swaps matrix elements while retaining the original dimensional form of the matrix. - const auto type = expression_type(id); - if (type.columns != type.vecsize) - SPIRV_CROSS_THROW("Row-major matrices must be square on this platform."); - - return true; + auto *e = maybe_get(id); + if (e) + return e->need_transpose; + else + return has_decoration(id, DecorationRowMajor); } // Checks whether the member is a row_major matrix that requires conversion before use @@ -14484,7 +14477,7 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s } } -void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) +void CompilerGLSL::cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) { auto *var = maybe_get_backing_variable(source_id); if (var) @@ -14536,7 +14529,7 @@ void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &ex expr = bitcast_expression(expr_type, expected_type, expr); } -void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) +void CompilerGLSL::cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) { // Only interested in standalone builtin variables. if (!has_decoration(target_id, DecorationBuiltIn)) diff --git a/3rdparty/spirv-cross/spirv_glsl.hpp b/3rdparty/spirv-cross/spirv_glsl.hpp index 33625f381..d81254561 100644 --- a/3rdparty/spirv-cross/spirv_glsl.hpp +++ b/3rdparty/spirv-cross/spirv_glsl.hpp @@ -854,9 +854,9 @@ protected: // Builtins in GLSL are always specific signedness, but the SPIR-V can declare them // as either unsigned or signed. - // Sometimes we will need to automatically perform bitcasts on load and store to make this work. - virtual void bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type); - virtual void bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type); + // Sometimes we will need to automatically perform casts on load and store to make this work. + virtual void cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type); + virtual void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type); void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr); void convert_non_uniform_expression(const SPIRType &type, std::string &expr); diff --git a/3rdparty/spirv-cross/spirv_msl.cpp b/3rdparty/spirv-cross/spirv_msl.cpp index cb6050b52..629b873f6 100644 --- a/3rdparty/spirv-cross/spirv_msl.cpp +++ b/3rdparty/spirv-cross/spirv_msl.cpp @@ -1120,7 +1120,7 @@ string CompilerMSL::compile() backend.basic_int16_type = "short"; backend.basic_uint16_type = "ushort"; backend.discard_literal = "discard_fragment()"; - backend.demote_literal = "unsupported-demote"; + backend.demote_literal = "discard_fragment()"; backend.boolean_mix_function = "select"; backend.swizzle_is_function = false; backend.shared_is_implied = false; @@ -4194,8 +4194,25 @@ void CompilerMSL::emit_custom_functions() // Emulate texture2D atomic operations case SPVFuncImplImage2DAtomicCoords: { + if (msl_options.supports_msl_version(1, 2)) + { + statement("// The required alignment of a linear texture of R32Uint format."); + statement("constant uint spvLinearTextureAlignmentOverride [[function_constant(", + msl_options.r32ui_alignment_constant_id, ")]];"); + statement("constant uint spvLinearTextureAlignment = ", + "is_function_constant_defined(spvLinearTextureAlignmentOverride) ? ", + "spvLinearTextureAlignmentOverride : ", msl_options.r32ui_linear_texture_alignment, ";"); + } + else + { + statement("// The required alignment of a linear texture of R32Uint format."); + statement("constant uint spvLinearTextureAlignment = ", msl_options.r32ui_linear_texture_alignment, + ";"); + } statement("// Returns buffer coords corresponding to 2D texture coords for emulating 2D texture atomics"); - statement("#define spvImage2DAtomicCoord(tc, tex) (((tex).get_width() * (tc).x) + (tc).y)"); + statement("#define spvImage2DAtomicCoord(tc, tex) (((((tex).get_width() + ", + " spvLinearTextureAlignment / 4 - 1) & ~(", + " spvLinearTextureAlignment / 4 - 1)) * (tc).y) + (tc).x)"); statement(""); break; } @@ -7117,11 +7134,18 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; } + // SPV_EXT_demote_to_helper_invocation + case OpDemoteToHelperInvocationEXT: + if (!msl_options.supports_msl_version(2, 3)) + SPIRV_CROSS_THROW("discard_fragment() does not formally have demote semantics until MSL 2.3."); + CompilerGLSL::emit_instruction(instruction); + break; + case OpIsHelperInvocationEXT: - if (msl_options.is_ios()) - SPIRV_CROSS_THROW("simd_is_helper_thread() is only supported on macOS."); + if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires MSL 2.3 on iOS."); else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) - SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS."); + SPIRV_CROSS_THROW("simd_is_helper_thread() requires MSL 2.1 on macOS."); emit_op(ops[0], ops[1], "simd_is_helper_thread()", false); break; @@ -10192,7 +10216,10 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) { ep_args += ", device atomic_" + type_to_glsl(get(basetype.image.type), 0); ep_args += "* " + r.name + "_atomic"; - ep_args += " [[buffer(" + convert_to_string(r.secondary_index) + ")]]"; + ep_args += " [[buffer(" + convert_to_string(r.secondary_index) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; } break; } @@ -13272,7 +13299,7 @@ void CompilerMSL::remap_constexpr_sampler_by_binding(uint32_t desc_set, uint32_t constexpr_samplers_by_binding[{ desc_set, binding }] = sampler; } -void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) +void CompilerMSL::cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) { auto *var = maybe_get_backing_variable(source_id); if (var) @@ -13284,6 +13311,7 @@ void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &exp auto builtin = static_cast(get_decoration(source_id, DecorationBuiltIn)); auto expected_type = expr_type.basetype; + auto expected_width = expr_type.width; switch (builtin) { case BuiltInGlobalInvocationId: @@ -13304,12 +13332,16 @@ void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &exp case BuiltInBaseInstance: case BuiltInBaseVertex: expected_type = SPIRType::UInt; + expected_width = 32; break; case BuiltInTessLevelInner: case BuiltInTessLevelOuter: if (get_execution_model() == ExecutionModelTessellationControl) + { expected_type = SPIRType::Half; + expected_width = 16; + } break; default: @@ -13317,7 +13349,17 @@ void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &exp } if (expected_type != expr_type.basetype) - expr = bitcast_expression(expr_type, expected_type, expr); + { + if (expected_width != expr_type.width) + { + // These are of different widths, so we cannot do a straight bitcast. + expr = join(type_to_glsl(expr_type), "(", expr, ")"); + } + else + { + expr = bitcast_expression(expr_type, expected_type, expr); + } + } if (builtin == BuiltInTessCoord && get_entry_point().flags.get(ExecutionModeQuads) && expr_type.vecsize == 3) { @@ -13327,7 +13369,7 @@ void CompilerMSL::bitcast_from_builtin_load(uint32_t source_id, std::string &exp } } -void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) +void CompilerMSL::cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) { auto *var = maybe_get_backing_variable(target_id); if (var) @@ -13339,6 +13381,7 @@ void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr auto builtin = static_cast(get_decoration(target_id, DecorationBuiltIn)); auto expected_type = expr_type.basetype; + auto expected_width = expr_type.width; switch (builtin) { case BuiltInLayer: @@ -13347,11 +13390,13 @@ void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr case BuiltInPrimitiveId: case BuiltInViewIndex: expected_type = SPIRType::UInt; + expected_width = 32; break; case BuiltInTessLevelInner: case BuiltInTessLevelOuter: expected_type = SPIRType::Half; + expected_width = 16; break; default: @@ -13360,10 +13405,13 @@ void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr if (expected_type != expr_type.basetype) { - if (expected_type == SPIRType::Half && expr_type.basetype == SPIRType::Float) + if (expected_width != expr_type.width) { // These are of different widths, so we cannot do a straight bitcast. - expr = join("half(", expr, ")"); + auto type = expr_type; + type.basetype = expected_type; + type.width = expected_width; + expr = join(type_to_glsl(type), "(", expr, ")"); } else { @@ -13500,6 +13548,14 @@ void CompilerMSL::analyze_argument_buffers() add_resource_name(var_id); resources_in_set[desc_set].push_back( { &var, to_name(var_id), type.basetype, get_metal_resource_index(var, type.basetype), 0 }); + + // Emulate texture2D atomic operations + if (atomic_image_vars.count(var.self)) + { + uint32_t buffer_resource_index = get_metal_resource_index(var, SPIRType::AtomicCounter, 0); + resources_in_set[desc_set].push_back( + { &var, to_name(var_id) + "_atomic", SPIRType::Struct, buffer_resource_index, 0 }); + } } } @@ -13675,6 +13731,30 @@ void CompilerMSL::analyze_argument_buffers() buffer_type.member_types.push_back(get_variable_data_type_id(var)); set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name)); } + else if (atomic_image_vars.count(var.self)) + { + // Emulate texture2D atomic operations. + // Don't set the qualified name: it's already set for this variable, + // and the code that references the buffer manually appends "_atomic" + // to the name. + uint32_t offset = ir.increase_bound_by(2); + uint32_t atomic_type_id = offset; + uint32_t type_ptr_id = offset + 1; + + SPIRType atomic_type; + atomic_type.basetype = SPIRType::AtomicCounter; + atomic_type.width = 32; + atomic_type.vecsize = 1; + set(atomic_type_id, atomic_type); + + atomic_type.pointer = true; + atomic_type.parent_type = atomic_type_id; + atomic_type.storage = StorageClassStorageBuffer; + auto &atomic_ptr_type = set(type_ptr_id, atomic_type); + atomic_ptr_type.self = atomic_type_id; + + buffer_type.member_types.push_back(type_ptr_id); + } else { // Resources will be declared as pointers not references, so automatically dereference as appropriate. @@ -13712,3 +13792,13 @@ bool CompilerMSL::using_builtin_array() const { return msl_options.force_native_arrays || is_using_builtin_array; } + +void CompilerMSL::set_combined_sampler_suffix(const char *suffix) +{ + sampler_name_suffix = suffix; +} + +const char *CompilerMSL::get_combined_sampler_suffix() const +{ + return sampler_name_suffix.c_str(); +} diff --git a/3rdparty/spirv-cross/spirv_msl.hpp b/3rdparty/spirv-cross/spirv_msl.hpp index 02f0ccfab..d8b801e71 100644 --- a/3rdparty/spirv-cross/spirv_msl.hpp +++ b/3rdparty/spirv-cross/spirv_msl.hpp @@ -268,6 +268,8 @@ 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 r32ui_linear_texture_alignment = 4; + uint32_t r32ui_alignment_constant_id = 65535; uint32_t swizzle_buffer_index = 30; uint32_t indirect_params_buffer_index = 29; uint32_t shader_output_buffer_index = 28; @@ -556,6 +558,9 @@ public: // to use for a particular location. The default is 4 if number of components is not overridden. void set_fragment_output_components(uint32_t location, uint32_t components); + void set_combined_sampler_suffix(const char *suffix); + const char *get_combined_sampler_suffix() const; + protected: // An enum of SPIR-V functions that are implemented in additional // source code that is added to the shader if necessary. @@ -842,8 +847,8 @@ protected: bool does_shader_write_sample_mask = false; - 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 cast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override; + void cast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override; void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression) override; void analyze_sampled_image_usage();