| 1 | /* | 
| 2 |  * Copyright 2015-2021 Arm Limited | 
| 3 |  * SPDX-License-Identifier: Apache-2.0 OR MIT | 
| 4 |  * | 
| 5 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
| 6 |  * you may not use this file except in compliance with the License. | 
| 7 |  * You may obtain a copy of the License at | 
| 8 |  * | 
| 9 |  *     http://www.apache.org/licenses/LICENSE-2.0 | 
| 10 |  * | 
| 11 |  * Unless required by applicable law or agreed to in writing, software | 
| 12 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 13 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 14 |  * See the License for the specific language governing permissions and | 
| 15 |  * limitations under the License. | 
| 16 |  */ | 
| 17 |  | 
| 18 | /* | 
| 19 |  * At your option, you may choose to accept this material under either: | 
| 20 |  *  1. The Apache License, Version 2.0, found at <http://www.apache.org/licenses/LICENSE-2.0>, or | 
| 21 |  *  2. The MIT License, found at <http://opensource.org/licenses/MIT>. | 
| 22 |  */ | 
| 23 |  | 
| 24 | #ifndef SPIRV_CROSS_GLSL_HPP | 
| 25 | #define SPIRV_CROSS_GLSL_HPP | 
| 26 |  | 
| 27 | #include "GLSL.std.450.h" | 
| 28 | #include "spirv_cross.hpp" | 
| 29 | #include <unordered_map> | 
| 30 | #include <unordered_set> | 
| 31 | #include <utility> | 
| 32 |  | 
| 33 | namespace SPIRV_CROSS_NAMESPACE | 
| 34 | { | 
| 35 | enum PlsFormat | 
| 36 | { | 
| 37 | 	PlsNone = 0, | 
| 38 |  | 
| 39 | 	PlsR11FG11FB10F, | 
| 40 | 	PlsR32F, | 
| 41 | 	PlsRG16F, | 
| 42 | 	PlsRGB10A2, | 
| 43 | 	PlsRGBA8, | 
| 44 | 	PlsRG16, | 
| 45 |  | 
| 46 | 	PlsRGBA8I, | 
| 47 | 	PlsRG16I, | 
| 48 |  | 
| 49 | 	PlsRGB10A2UI, | 
| 50 | 	PlsRGBA8UI, | 
| 51 | 	PlsRG16UI, | 
| 52 | 	PlsR32UI | 
| 53 | }; | 
| 54 |  | 
| 55 | struct PlsRemap | 
| 56 | { | 
| 57 | 	uint32_t id; | 
| 58 | 	PlsFormat format; | 
| 59 | }; | 
| 60 |  | 
| 61 | enum AccessChainFlagBits | 
| 62 | { | 
| 63 | 	ACCESS_CHAIN_INDEX_IS_LITERAL_BIT = 1 << 0, | 
| 64 | 	ACCESS_CHAIN_CHAIN_ONLY_BIT = 1 << 1, | 
| 65 | 	ACCESS_CHAIN_PTR_CHAIN_BIT = 1 << 2, | 
| 66 | 	ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT = 1 << 3, | 
| 67 | 	ACCESS_CHAIN_LITERAL_MSB_FORCE_ID = 1 << 4, | 
| 68 | 	ACCESS_CHAIN_FLATTEN_ALL_MEMBERS_BIT = 1 << 5, | 
| 69 | 	ACCESS_CHAIN_FORCE_COMPOSITE_BIT = 1 << 6 | 
| 70 | }; | 
| 71 | typedef uint32_t AccessChainFlags; | 
| 72 |  | 
| 73 | class CompilerGLSL : public Compiler | 
| 74 | { | 
| 75 | public: | 
| 76 | 	struct Options | 
| 77 | 	{ | 
| 78 | 		// The shading language version. Corresponds to #version $VALUE. | 
| 79 | 		uint32_t version = 450; | 
| 80 |  | 
| 81 | 		// Emit the OpenGL ES shading language instead of desktop OpenGL. | 
| 82 | 		bool es = false; | 
| 83 |  | 
| 84 | 		// Debug option to always emit temporary variables for all expressions. | 
| 85 | 		bool force_temporary = false; | 
| 86 | 		// Debug option, can be increased in an attempt to workaround SPIRV-Cross bugs temporarily. | 
| 87 | 		// If this limit has to be increased, it points to an implementation bug. | 
| 88 | 		// In certain scenarios, the maximum number of debug iterations may increase beyond this limit | 
| 89 | 		// as long as we can prove we're making certain kinds of forward progress. | 
| 90 | 		uint32_t force_recompile_max_debug_iterations = 3; | 
| 91 |  | 
| 92 | 		// If true, Vulkan GLSL features are used instead of GL-compatible features. | 
| 93 | 		// Mostly useful for debugging SPIR-V files. | 
| 94 | 		bool vulkan_semantics = false; | 
| 95 |  | 
| 96 | 		// If true, gl_PerVertex is explicitly redeclared in vertex, geometry and tessellation shaders. | 
| 97 | 		// The members of gl_PerVertex is determined by which built-ins are declared by the shader. | 
| 98 | 		// This option is ignored in ES versions, as redeclaration in ES is not required, and it depends on a different extension | 
| 99 | 		// (EXT_shader_io_blocks) which makes things a bit more fuzzy. | 
| 100 | 		bool separate_shader_objects = false; | 
| 101 |  | 
| 102 | 		// Flattens multidimensional arrays, e.g. float foo[a][b][c] into single-dimensional arrays, | 
| 103 | 		// e.g. float foo[a * b * c]. | 
| 104 | 		// This function does not change the actual SPIRType of any object. | 
| 105 | 		// Only the generated code, including declarations of interface variables are changed to be single array dimension. | 
| 106 | 		bool flatten_multidimensional_arrays = false; | 
| 107 |  | 
| 108 | 		// For older desktop GLSL targets than version 420, the | 
| 109 | 		// GL_ARB_shading_language_420pack extensions is used to be able to support | 
| 110 | 		// layout(binding) on UBOs and samplers. | 
| 111 | 		// If disabled on older targets, binding decorations will be stripped. | 
| 112 | 		bool enable_420pack_extension = true; | 
| 113 |  | 
| 114 | 		// In non-Vulkan GLSL, emit push constant blocks as UBOs rather than plain uniforms. | 
| 115 | 		bool emit_push_constant_as_uniform_buffer = false; | 
| 116 |  | 
| 117 | 		// Always emit uniform blocks as plain uniforms, regardless of the GLSL version, even when UBOs are supported. | 
| 118 | 		// Does not apply to shader storage or push constant blocks. | 
| 119 | 		bool emit_uniform_buffer_as_plain_uniforms = false; | 
| 120 |  | 
| 121 | 		// Emit OpLine directives if present in the module. | 
| 122 | 		// May not correspond exactly to original source, but should be a good approximation. | 
| 123 | 		bool emit_line_directives = false; | 
| 124 |  | 
| 125 | 		// In cases where readonly/writeonly decoration are not used at all, | 
| 126 | 		// we try to deduce which qualifier(s) we should actually used, since actually emitting | 
| 127 | 		// read-write decoration is very rare, and older glslang/HLSL compilers tend to just emit readwrite as a matter of fact. | 
| 128 | 		// The default (true) is to enable automatic deduction for these cases, but if you trust the decorations set | 
| 129 | 		// by the SPIR-V, it's recommended to set this to false. | 
| 130 | 		bool enable_storage_image_qualifier_deduction = true; | 
| 131 |  | 
| 132 | 		// On some targets (WebGPU), uninitialized variables are banned. | 
| 133 | 		// If this is enabled, all variables (temporaries, Private, Function) | 
| 134 | 		// which would otherwise be uninitialized will now be initialized to 0 instead. | 
| 135 | 		bool force_zero_initialized_variables = false; | 
| 136 |  | 
| 137 | 		// In GLSL, force use of I/O block flattening, similar to | 
| 138 | 		// what happens on legacy GLSL targets for blocks and structs. | 
| 139 | 		bool force_flattened_io_blocks = false; | 
| 140 |  | 
| 141 | 		// For opcodes where we have to perform explicit additional nan checks, very ugly code is generated. | 
| 142 | 		// If we opt-in, ignore these requirements. | 
| 143 | 		// In opcodes like NClamp/NMin/NMax and FP compare, ignore NaN behavior. | 
| 144 | 		// Use FClamp/FMin/FMax semantics for clamps and lets implementation choose ordered or unordered | 
| 145 | 		// compares. | 
| 146 | 		bool relax_nan_checks = false; | 
| 147 |  | 
| 148 | 		// Loading row-major matrices from UBOs on older AMD Windows OpenGL drivers is problematic. | 
| 149 | 		// To load these types correctly, we must generate a wrapper. them in a dummy function which only purpose is to | 
| 150 | 		// ensure row_major decoration is actually respected. | 
| 151 | 		// This workaround may cause significant performance degeneration on some Android devices. | 
| 152 | 		bool enable_row_major_load_workaround = true; | 
| 153 |  | 
| 154 | 		// If non-zero, controls layout(num_views = N) in; in GL_OVR_multiview2. | 
| 155 | 		uint32_t ovr_multiview_view_count = 0; | 
| 156 |  | 
| 157 | 		enum Precision | 
| 158 | 		{ | 
| 159 | 			DontCare, | 
| 160 | 			Lowp, | 
| 161 | 			Mediump, | 
| 162 | 			Highp | 
| 163 | 		}; | 
| 164 |  | 
| 165 | 		struct VertexOptions | 
| 166 | 		{ | 
| 167 | 			// "Vertex-like shader" here is any shader stage that can write BuiltInPosition. | 
| 168 |  | 
| 169 | 			// GLSL: In vertex-like shaders, rewrite [0, w] depth (Vulkan/D3D style) to [-w, w] depth (GL style). | 
| 170 | 			// MSL: In vertex-like shaders, rewrite [-w, w] depth (GL style) to [0, w] depth. | 
| 171 | 			// HLSL: In vertex-like shaders, rewrite [-w, w] depth (GL style) to [0, w] depth. | 
| 172 | 			bool fixup_clipspace = false; | 
| 173 |  | 
| 174 | 			// In vertex-like shaders, inverts gl_Position.y or equivalent. | 
| 175 | 			bool flip_vert_y = false; | 
| 176 |  | 
| 177 | 			// GLSL only, for HLSL version of this option, see CompilerHLSL. | 
| 178 | 			// If true, the backend will assume that InstanceIndex will need to apply | 
| 179 | 			// a base instance offset. Set to false if you know you will never use base instance | 
| 180 | 			// functionality as it might remove some internal uniforms. | 
| 181 | 			bool support_nonzero_base_instance = true; | 
| 182 | 		} vertex; | 
| 183 |  | 
| 184 | 		struct FragmentOptions | 
| 185 | 		{ | 
| 186 | 			// Add precision mediump float in ES targets when emitting GLES source. | 
| 187 | 			// Add precision highp int in ES targets when emitting GLES source. | 
| 188 | 			Precision default_float_precision = Mediump; | 
| 189 | 			Precision default_int_precision = Highp; | 
| 190 | 		} fragment; | 
| 191 | 	}; | 
| 192 |  | 
| 193 | 	void remap_pixel_local_storage(std::vector<PlsRemap> inputs, std::vector<PlsRemap> outputs) | 
| 194 | 	{ | 
| 195 | 		pls_inputs = std::move(inputs); | 
| 196 | 		pls_outputs = std::move(outputs); | 
| 197 | 		remap_pls_variables(); | 
| 198 | 	} | 
| 199 |  | 
| 200 | 	// Redirect a subpassInput reading from input_attachment_index to instead load its value from | 
| 201 | 	// the color attachment at location = color_location. Requires ESSL. | 
| 202 | 	// If coherent, uses GL_EXT_shader_framebuffer_fetch, if not, uses noncoherent variant. | 
| 203 | 	void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location, bool coherent); | 
| 204 |  | 
| 205 | 	explicit CompilerGLSL(std::vector<uint32_t> spirv_) | 
| 206 | 	    : Compiler(std::move(spirv_)) | 
| 207 | 	{ | 
| 208 | 		init(); | 
| 209 | 	} | 
| 210 |  | 
| 211 | 	CompilerGLSL(const uint32_t *ir_, size_t word_count) | 
| 212 | 	    : Compiler(ir_, word_count) | 
| 213 | 	{ | 
| 214 | 		init(); | 
| 215 | 	} | 
| 216 |  | 
| 217 | 	explicit CompilerGLSL(const ParsedIR &ir_) | 
| 218 | 	    : Compiler(ir_) | 
| 219 | 	{ | 
| 220 | 		init(); | 
| 221 | 	} | 
| 222 |  | 
| 223 | 	explicit CompilerGLSL(ParsedIR &&ir_) | 
| 224 | 	    : Compiler(std::move(ir_)) | 
| 225 | 	{ | 
| 226 | 		init(); | 
| 227 | 	} | 
| 228 |  | 
| 229 | 	const Options &get_common_options() const | 
| 230 | 	{ | 
| 231 | 		return options; | 
| 232 | 	} | 
| 233 |  | 
| 234 | 	void set_common_options(const Options &opts) | 
| 235 | 	{ | 
| 236 | 		options = opts; | 
| 237 | 	} | 
| 238 |  | 
| 239 | 	std::string compile() override; | 
| 240 |  | 
| 241 | 	// Returns the current string held in the conversion buffer. Useful for | 
| 242 | 	// capturing what has been converted so far when compile() throws an error. | 
| 243 | 	std::string get_partial_source(); | 
| 244 |  | 
| 245 | 	// Adds a line to be added right after #version in GLSL backend. | 
| 246 | 	// This is useful for enabling custom extensions which are outside the scope of SPIRV-Cross. | 
| 247 | 	// This can be combined with variable remapping. | 
| 248 | 	// A new-line will be added. | 
| 249 | 	// | 
| 250 | 	// While add_header_line() is a more generic way of adding arbitrary text to the header | 
| 251 | 	// of a GLSL file, require_extension() should be used when adding extensions since it will | 
| 252 | 	// avoid creating collisions with SPIRV-Cross generated extensions. | 
| 253 | 	// | 
| 254 | 	// Code added via add_header_line() is typically backend-specific. | 
| 255 | 	void (const std::string &str); | 
| 256 |  | 
| 257 | 	// Adds an extension which is required to run this shader, e.g. | 
| 258 | 	// require_extension("GL_KHR_my_extension"); | 
| 259 | 	void require_extension(const std::string &ext); | 
| 260 |  | 
| 261 | 	// Returns the list of required extensions. After compilation this will contains any other  | 
| 262 | 	// extensions that the compiler used automatically, in addition to the user specified ones. | 
| 263 | 	const SmallVector<std::string> &get_required_extensions() const; | 
| 264 |  | 
| 265 | 	// Legacy GLSL compatibility method. | 
| 266 | 	// Takes a uniform or push constant variable and flattens it into a (i|u)vec4 array[N]; array instead. | 
| 267 | 	// For this to work, all types in the block must be the same basic type, e.g. mixing vec2 and vec4 is fine, but | 
| 268 | 	// mixing int and float is not. | 
| 269 | 	// The name of the uniform array will be the same as the interface block name. | 
| 270 | 	void flatten_buffer_block(VariableID id); | 
| 271 |  | 
| 272 | 	// After compilation, query if a variable ID was used as a depth resource. | 
| 273 | 	// This is meaningful for MSL since descriptor types depend on this knowledge. | 
| 274 | 	// Cases which return true: | 
| 275 | 	// - Images which are declared with depth = 1 image type. | 
| 276 | 	// - Samplers which are statically used at least once with Dref opcodes. | 
| 277 | 	// - Images which are statically used at least once with Dref opcodes. | 
| 278 | 	bool variable_is_depth_or_compare(VariableID id) const; | 
| 279 |  | 
| 280 | 	// If a shader output is active in this stage, but inactive in a subsequent stage, | 
| 281 | 	// this can be signalled here. This can be used to work around certain cross-stage matching problems | 
| 282 | 	// which plagues MSL and HLSL in certain scenarios. | 
| 283 | 	// An output which matches one of these will not be emitted in stage output interfaces, but rather treated as a private | 
| 284 | 	// variable. | 
| 285 | 	// This option is only meaningful for MSL and HLSL, since GLSL matches by location directly. | 
| 286 | 	// Masking builtins only takes effect if the builtin in question is part of the stage output interface. | 
| 287 | 	void mask_stage_output_by_location(uint32_t location, uint32_t component); | 
| 288 | 	void mask_stage_output_by_builtin(spv::BuiltIn builtin); | 
| 289 |  | 
| 290 | 	// Allow to control how to format float literals in the output. | 
| 291 | 	// Set to "nullptr" to use the default "convert_to_string" function. | 
| 292 | 	// This handle is not owned by SPIRV-Cross and must remain valid until compile() has been called. | 
| 293 | 	void set_float_formatter(FloatFormatter *formatter) | 
| 294 | 	{ | 
| 295 | 		float_formatter = formatter; | 
| 296 | 	} | 
| 297 |  | 
| 298 | protected: | 
| 299 | 	struct ShaderSubgroupSupportHelper | 
| 300 | 	{ | 
| 301 | 		// lower enum value = greater priority | 
| 302 | 		enum Candidate | 
| 303 | 		{ | 
| 304 | 			KHR_shader_subgroup_ballot, | 
| 305 | 			KHR_shader_subgroup_basic, | 
| 306 | 			KHR_shader_subgroup_vote, | 
| 307 | 			KHR_shader_subgroup_arithmetic, | 
| 308 | 			NV_gpu_shader_5, | 
| 309 | 			NV_shader_thread_group, | 
| 310 | 			NV_shader_thread_shuffle, | 
| 311 | 			ARB_shader_ballot, | 
| 312 | 			ARB_shader_group_vote, | 
| 313 | 			AMD_gcn_shader, | 
| 314 |  | 
| 315 | 			CandidateCount | 
| 316 | 		}; | 
| 317 |  | 
| 318 | 		static const char *get_extension_name(Candidate c); | 
| 319 | 		static SmallVector<std::string> get_extra_required_extension_names(Candidate c); | 
| 320 | 		static const char *get_extra_required_extension_predicate(Candidate c); | 
| 321 |  | 
| 322 | 		enum Feature | 
| 323 | 		{ | 
| 324 | 			SubgroupMask = 0, | 
| 325 | 			SubgroupSize = 1, | 
| 326 | 			SubgroupInvocationID = 2, | 
| 327 | 			SubgroupID = 3, | 
| 328 | 			NumSubgroups = 4, | 
| 329 | 			SubgroupBroadcast_First = 5, | 
| 330 | 			SubgroupBallotFindLSB_MSB = 6, | 
| 331 | 			SubgroupAll_Any_AllEqualBool = 7, | 
| 332 | 			SubgroupAllEqualT = 8, | 
| 333 | 			SubgroupElect = 9, | 
| 334 | 			SubgroupBarrier = 10, | 
| 335 | 			SubgroupMemBarrier = 11, | 
| 336 | 			SubgroupBallot = 12, | 
| 337 | 			SubgroupInverseBallot_InclBitCount_ExclBitCout = 13, | 
| 338 | 			 = 14, | 
| 339 | 			SubgroupBallotBitCount = 15, | 
| 340 | 			SubgroupArithmeticIAddReduce = 16, | 
| 341 | 			SubgroupArithmeticIAddExclusiveScan = 17, | 
| 342 | 			SubgroupArithmeticIAddInclusiveScan = 18, | 
| 343 | 			SubgroupArithmeticFAddReduce = 19, | 
| 344 | 			SubgroupArithmeticFAddExclusiveScan = 20, | 
| 345 | 			SubgroupArithmeticFAddInclusiveScan = 21, | 
| 346 | 			SubgroupArithmeticIMulReduce = 22, | 
| 347 | 			SubgroupArithmeticIMulExclusiveScan = 23, | 
| 348 | 			SubgroupArithmeticIMulInclusiveScan = 24, | 
| 349 | 			SubgroupArithmeticFMulReduce = 25, | 
| 350 | 			SubgroupArithmeticFMulExclusiveScan = 26, | 
| 351 | 			SubgroupArithmeticFMulInclusiveScan = 27, | 
| 352 | 			FeatureCount | 
| 353 | 		}; | 
| 354 |  | 
| 355 | 		using FeatureMask = uint32_t; | 
| 356 | 		static_assert(sizeof(FeatureMask) * 8u >= FeatureCount, "Mask type needs more bits." ); | 
| 357 |  | 
| 358 | 		using CandidateVector = SmallVector<Candidate, CandidateCount>; | 
| 359 | 		using FeatureVector = SmallVector<Feature>; | 
| 360 |  | 
| 361 | 		static FeatureVector get_feature_dependencies(Feature feature); | 
| 362 | 		static FeatureMask get_feature_dependency_mask(Feature feature); | 
| 363 | 		static bool can_feature_be_implemented_without_extensions(Feature feature); | 
| 364 | 		static Candidate get_KHR_extension_for_feature(Feature feature); | 
| 365 |  | 
| 366 | 		struct Result | 
| 367 | 		{ | 
| 368 | 			Result(); | 
| 369 | 			uint32_t weights[CandidateCount]; | 
| 370 | 		}; | 
| 371 |  | 
| 372 | 		void request_feature(Feature feature); | 
| 373 | 		bool is_feature_requested(Feature feature) const; | 
| 374 | 		Result resolve() const; | 
| 375 |  | 
| 376 | 		static CandidateVector get_candidates_for_feature(Feature ft, const Result &r); | 
| 377 |  | 
| 378 | 	private: | 
| 379 | 		static CandidateVector get_candidates_for_feature(Feature ft); | 
| 380 | 		static FeatureMask build_mask(const SmallVector<Feature> &features); | 
| 381 | 		FeatureMask feature_mask = 0; | 
| 382 | 	}; | 
| 383 |  | 
| 384 | 	// TODO remove this function when all subgroup ops are supported (or make it always return true) | 
| 385 | 	static bool is_supported_subgroup_op_in_opengl(spv::Op op, const uint32_t *ops); | 
| 386 |  | 
| 387 | 	void reset(uint32_t iteration_count); | 
| 388 | 	void emit_function(SPIRFunction &func, const Bitset &return_flags); | 
| 389 |  | 
| 390 | 	bool has_extension(const std::string &ext) const; | 
| 391 | 	void require_extension_internal(const std::string &ext); | 
| 392 |  | 
| 393 | 	// Virtualize methods which need to be overridden by subclass targets like C++ and such. | 
| 394 | 	virtual void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags); | 
| 395 |  | 
| 396 | 	SPIRBlock *current_emitting_block = nullptr; | 
| 397 | 	SmallVector<SPIRBlock *> current_emitting_switch_stack; | 
| 398 | 	bool current_emitting_switch_fallthrough = false; | 
| 399 |  | 
| 400 | 	virtual void emit_instruction(const Instruction &instr); | 
| 401 | 	struct TemporaryCopy | 
| 402 | 	{ | 
| 403 | 		uint32_t dst_id; | 
| 404 | 		uint32_t src_id; | 
| 405 | 	}; | 
| 406 | 	TemporaryCopy handle_instruction_precision(const Instruction &instr); | 
| 407 | 	void emit_block_instructions(SPIRBlock &block); | 
| 408 | 	void emit_block_instructions_with_masked_debug(SPIRBlock &block); | 
| 409 |  | 
| 410 | 	// For relax_nan_checks. | 
| 411 | 	GLSLstd450 get_remapped_glsl_op(GLSLstd450 std450_op) const; | 
| 412 | 	spv::Op get_remapped_spirv_op(spv::Op op) const; | 
| 413 |  | 
| 414 | 	virtual void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, | 
| 415 | 	                          uint32_t count); | 
| 416 | 	virtual void emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t result_id, uint32_t op, | 
| 417 | 	                                           const uint32_t *args, uint32_t count); | 
| 418 | 	virtual void emit_spv_amd_shader_explicit_vertex_parameter_op(uint32_t result_type, uint32_t result_id, uint32_t op, | 
| 419 | 	                                                              const uint32_t *args, uint32_t count); | 
| 420 | 	virtual void emit_spv_amd_shader_trinary_minmax_op(uint32_t result_type, uint32_t result_id, uint32_t op, | 
| 421 | 	                                                   const uint32_t *args, uint32_t count); | 
| 422 | 	virtual void emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, | 
| 423 | 	                                        uint32_t count); | 
| 424 | 	virtual void (); | 
| 425 | 	void emit_line_directive(uint32_t file_id, uint32_t line_literal); | 
| 426 | 	void build_workgroup_size(SmallVector<std::string> &arguments, const SpecializationConstant &x, | 
| 427 | 	                          const SpecializationConstant &y, const SpecializationConstant &z); | 
| 428 |  | 
| 429 | 	void request_subgroup_feature(ShaderSubgroupSupportHelper::Feature feature); | 
| 430 |  | 
| 431 | 	virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id); | 
| 432 | 	virtual void emit_texture_op(const Instruction &i, bool sparse); | 
| 433 | 	virtual std::string to_texture_op(const Instruction &i, bool sparse, bool *forward, | 
| 434 | 	                                  SmallVector<uint32_t> &inherited_expressions); | 
| 435 | 	virtual void emit_subgroup_op(const Instruction &i); | 
| 436 | 	virtual std::string type_to_glsl(const SPIRType &type, uint32_t id = 0); | 
| 437 | 	virtual std::string builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage); | 
| 438 | 	virtual void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, | 
| 439 | 	                                const std::string &qualifier = "" , uint32_t base_offset = 0); | 
| 440 | 	virtual void emit_struct_padding_target(const SPIRType &type); | 
| 441 | 	virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0, bool member = false); | 
| 442 | 	std::string constant_expression(const SPIRConstant &c, | 
| 443 | 	                                bool inside_block_like_struct_scope = false, | 
| 444 | 	                                bool inside_struct_scope = false); | 
| 445 | 	virtual std::string constant_op_expression(const SPIRConstantOp &cop); | 
| 446 | 	virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector); | 
| 447 | 	virtual void emit_fixup(); | 
| 448 | 	virtual std::string variable_decl(const SPIRType &type, const std::string &name, uint32_t id = 0); | 
| 449 | 	virtual bool variable_decl_is_remapped_storage(const SPIRVariable &var, spv::StorageClass storage) const; | 
| 450 | 	virtual std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id); | 
| 451 |  | 
| 452 | 	struct TextureFunctionBaseArguments | 
| 453 | 	{ | 
| 454 | 		// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor. | 
| 455 | 		TextureFunctionBaseArguments() = default; | 
| 456 | 		VariableID img = 0; | 
| 457 | 		const SPIRType *imgtype = nullptr; | 
| 458 | 		bool is_fetch = false, is_gather = false, is_proj = false; | 
| 459 | 	}; | 
| 460 |  | 
| 461 | 	struct TextureFunctionNameArguments | 
| 462 | 	{ | 
| 463 | 		// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor. | 
| 464 | 		TextureFunctionNameArguments() = default; | 
| 465 | 		TextureFunctionBaseArguments base; | 
| 466 | 		bool has_array_offsets = false, has_offset = false, has_grad = false; | 
| 467 | 		bool has_dref = false, is_sparse_feedback = false, has_min_lod = false; | 
| 468 | 		uint32_t lod = 0; | 
| 469 | 	}; | 
| 470 | 	virtual std::string to_function_name(const TextureFunctionNameArguments &args); | 
| 471 |  | 
| 472 | 	struct TextureFunctionArguments | 
| 473 | 	{ | 
| 474 | 		// GCC 4.8 workarounds, it doesn't understand '{}' constructor here, use explicit default constructor. | 
| 475 | 		TextureFunctionArguments() = default; | 
| 476 | 		TextureFunctionBaseArguments base; | 
| 477 | 		uint32_t coord = 0, coord_components = 0, dref = 0; | 
| 478 | 		uint32_t grad_x = 0, grad_y = 0, lod = 0, offset = 0; | 
| 479 | 		uint32_t bias = 0, component = 0, sample = 0, sparse_texel = 0, min_lod = 0; | 
| 480 | 		bool nonuniform_expression = false, has_array_offsets = false; | 
| 481 | 	}; | 
| 482 | 	virtual std::string to_function_args(const TextureFunctionArguments &args, bool *p_forward); | 
| 483 |  | 
| 484 | 	void emit_sparse_feedback_temporaries(uint32_t result_type_id, uint32_t id, uint32_t &feedback_id, | 
| 485 | 	                                      uint32_t &texel_id); | 
| 486 | 	uint32_t get_sparse_feedback_texel_id(uint32_t id) const; | 
| 487 | 	virtual void emit_buffer_block(const SPIRVariable &type); | 
| 488 | 	virtual void emit_push_constant_block(const SPIRVariable &var); | 
| 489 | 	virtual void emit_uniform(const SPIRVariable &var); | 
| 490 | 	virtual std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id, | 
| 491 | 	                                           bool packed_type, bool row_major); | 
| 492 |  | 
| 493 | 	virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const; | 
| 494 |  | 
| 495 | 	virtual bool is_user_type_structured(uint32_t id) const; | 
| 496 |  | 
| 497 | 	void emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id, | 
| 498 | 	                            SmallVector<uint32_t> chain); | 
| 499 |  | 
| 500 | 	StringStream<> buffer; | 
| 501 |  | 
| 502 | 	template <typename T> | 
| 503 | 	inline void statement_inner(T &&t) | 
| 504 | 	{ | 
| 505 | 		buffer << std::forward<T>(t); | 
| 506 | 		statement_count++; | 
| 507 | 	} | 
| 508 |  | 
| 509 | 	template <typename T, typename... Ts> | 
| 510 | 	inline void statement_inner(T &&t, Ts &&... ts) | 
| 511 | 	{ | 
| 512 | 		buffer << std::forward<T>(t); | 
| 513 | 		statement_count++; | 
| 514 | 		statement_inner(std::forward<Ts>(ts)...); | 
| 515 | 	} | 
| 516 |  | 
| 517 | 	template <typename... Ts> | 
| 518 | 	inline void statement(Ts &&... ts) | 
| 519 | 	{ | 
| 520 | 		if (is_forcing_recompilation()) | 
| 521 | 		{ | 
| 522 | 			// Do not bother emitting code while force_recompile is active. | 
| 523 | 			// We will compile again. | 
| 524 | 			statement_count++; | 
| 525 | 			return; | 
| 526 | 		} | 
| 527 |  | 
| 528 | 		if (redirect_statement) | 
| 529 | 		{ | 
| 530 | 			redirect_statement->push_back(join(std::forward<Ts>(ts)...)); | 
| 531 | 			statement_count++; | 
| 532 | 		} | 
| 533 | 		else | 
| 534 | 		{ | 
| 535 | 			for (uint32_t i = 0; i < indent; i++) | 
| 536 | 				buffer << "    " ; | 
| 537 | 			statement_inner(std::forward<Ts>(ts)...); | 
| 538 | 			buffer << '\n'; | 
| 539 | 		} | 
| 540 | 	} | 
| 541 |  | 
| 542 | 	template <typename... Ts> | 
| 543 | 	inline void statement_no_indent(Ts &&... ts) | 
| 544 | 	{ | 
| 545 | 		auto old_indent = indent; | 
| 546 | 		indent = 0; | 
| 547 | 		statement(std::forward<Ts>(ts)...); | 
| 548 | 		indent = old_indent; | 
| 549 | 	} | 
| 550 |  | 
| 551 | 	// Used for implementing continue blocks where | 
| 552 | 	// we want to obtain a list of statements we can merge | 
| 553 | 	// on a single line separated by comma. | 
| 554 | 	SmallVector<std::string> *redirect_statement = nullptr; | 
| 555 | 	const SPIRBlock *current_continue_block = nullptr; | 
| 556 | 	bool block_temporary_hoisting = false; | 
| 557 | 	bool block_debug_directives = false; | 
| 558 |  | 
| 559 | 	void begin_scope(); | 
| 560 | 	void end_scope(); | 
| 561 | 	void end_scope(const std::string &trailer); | 
| 562 | 	void end_scope_decl(); | 
| 563 | 	void end_scope_decl(const std::string &decl); | 
| 564 |  | 
| 565 | 	Options options; | 
| 566 |  | 
| 567 | 	// Allow Metal to use the array<T> template to make arrays a value type | 
| 568 | 	virtual std::string type_to_array_glsl(const SPIRType &type, uint32_t variable_id); | 
| 569 | 	std::string to_array_size(const SPIRType &type, uint32_t index); | 
| 570 | 	uint32_t to_array_size_literal(const SPIRType &type, uint32_t index) const; | 
| 571 | 	uint32_t to_array_size_literal(const SPIRType &type) const; | 
| 572 | 	virtual std::string variable_decl(const SPIRVariable &variable); // Threadgroup arrays can't have a wrapper type | 
| 573 | 	std::string variable_decl_function_local(SPIRVariable &variable); | 
| 574 |  | 
| 575 | 	void add_local_variable_name(uint32_t id); | 
| 576 | 	void add_resource_name(uint32_t id); | 
| 577 | 	void add_member_name(SPIRType &type, uint32_t name); | 
| 578 | 	void add_function_overload(const SPIRFunction &func); | 
| 579 |  | 
| 580 | 	virtual bool is_non_native_row_major_matrix(uint32_t id); | 
| 581 | 	virtual bool member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index); | 
| 582 | 	bool member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const; | 
| 583 | 	bool member_is_packed_physical_type(const SPIRType &type, uint32_t index) const; | 
| 584 | 	virtual std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type, | 
| 585 | 	                                             uint32_t physical_type_id, bool is_packed, | 
| 586 | 	                                             bool relaxed = false); | 
| 587 |  | 
| 588 | 	std::unordered_set<std::string> local_variable_names; | 
| 589 | 	std::unordered_set<std::string> resource_names; | 
| 590 | 	std::unordered_set<std::string> block_input_names; | 
| 591 | 	std::unordered_set<std::string> block_output_names; | 
| 592 | 	std::unordered_set<std::string> block_ubo_names; | 
| 593 | 	std::unordered_set<std::string> block_ssbo_names; | 
| 594 | 	std::unordered_set<std::string> block_names; // A union of all block_*_names. | 
| 595 | 	std::unordered_map<std::string, std::unordered_set<uint64_t>> function_overloads; | 
| 596 | 	std::unordered_map<uint32_t, std::string> preserved_aliases; | 
| 597 | 	void preserve_alias_on_reset(uint32_t id); | 
| 598 | 	void reset_name_caches(); | 
| 599 |  | 
| 600 | 	bool processing_entry_point = false; | 
| 601 |  | 
| 602 | 	// Can be overriden by subclass backends for trivial things which | 
| 603 | 	// shouldn't need polymorphism. | 
| 604 | 	struct BackendVariations | 
| 605 | 	{ | 
| 606 | 		std::string discard_literal = "discard" ; | 
| 607 | 		std::string demote_literal = "demote" ; | 
| 608 | 		std::string null_pointer_literal = "" ; | 
| 609 | 		bool float_literal_suffix = false; | 
| 610 | 		bool double_literal_suffix = true; | 
| 611 | 		bool uint32_t_literal_suffix = true; | 
| 612 | 		bool long_long_literal_suffix = false; | 
| 613 | 		const char *basic_int_type = "int" ; | 
| 614 | 		const char *basic_uint_type = "uint" ; | 
| 615 | 		const char *basic_int8_type = "int8_t" ; | 
| 616 | 		const char *basic_uint8_type = "uint8_t" ; | 
| 617 | 		const char *basic_int16_type = "int16_t" ; | 
| 618 | 		const char *basic_uint16_type = "uint16_t" ; | 
| 619 | 		const char *int16_t_literal_suffix = "s" ; | 
| 620 | 		const char *uint16_t_literal_suffix = "us" ; | 
| 621 | 		const char *nonuniform_qualifier = "nonuniformEXT" ; | 
| 622 | 		const char *boolean_mix_function = "mix" ; | 
| 623 | 		SPIRType::BaseType boolean_in_struct_remapped_type = SPIRType::Boolean; | 
| 624 | 		bool swizzle_is_function = false; | 
| 625 | 		bool shared_is_implied = false; | 
| 626 | 		bool unsized_array_supported = true; | 
| 627 | 		bool explicit_struct_type = false; | 
| 628 | 		bool use_initializer_list = false; | 
| 629 | 		bool use_typed_initializer_list = false; | 
| 630 | 		bool can_declare_struct_inline = true; | 
| 631 | 		bool can_declare_arrays_inline = true; | 
| 632 | 		bool native_row_major_matrix = true; | 
| 633 | 		bool use_constructor_splatting = true; | 
| 634 | 		bool allow_precision_qualifiers = false; | 
| 635 | 		bool can_swizzle_scalar = false; | 
| 636 | 		bool force_gl_in_out_block = false; | 
| 637 | 		bool force_merged_mesh_block = false; | 
| 638 | 		bool can_return_array = true; | 
| 639 | 		bool allow_truncated_access_chain = false; | 
| 640 | 		bool supports_extensions = false; | 
| 641 | 		bool supports_empty_struct = false; | 
| 642 | 		bool array_is_value_type = true; | 
| 643 | 		bool array_is_value_type_in_buffer_blocks = true; | 
| 644 | 		bool comparison_image_samples_scalar = false; | 
| 645 | 		bool native_pointers = false; | 
| 646 | 		bool support_small_type_sampling_result = false; | 
| 647 | 		bool support_case_fallthrough = true; | 
| 648 | 		bool use_array_constructor = false; | 
| 649 | 		bool needs_row_major_load_workaround = false; | 
| 650 | 		bool support_pointer_to_pointer = false; | 
| 651 | 		bool support_precise_qualifier = false; | 
| 652 | 		bool support_64bit_switch = false; | 
| 653 | 		bool workgroup_size_is_hidden = false; | 
| 654 | 		bool requires_relaxed_precision_analysis = false; | 
| 655 | 		bool implicit_c_integer_promotion_rules = false; | 
| 656 | 	} backend; | 
| 657 |  | 
| 658 | 	void emit_struct(SPIRType &type); | 
| 659 | 	void emit_resources(); | 
| 660 | 	void emit_extension_workarounds(spv::ExecutionModel model); | 
| 661 | 	void emit_subgroup_arithmetic_workaround(const std::string &func, spv::Op op, spv::GroupOperation group_op); | 
| 662 | 	void emit_polyfills(uint32_t polyfills, bool relaxed); | 
| 663 | 	void emit_buffer_block_native(const SPIRVariable &var); | 
| 664 | 	void emit_buffer_reference_block(uint32_t type_id, bool forward_declaration); | 
| 665 | 	void emit_buffer_block_legacy(const SPIRVariable &var); | 
| 666 | 	void emit_buffer_block_flattened(const SPIRVariable &type); | 
| 667 | 	void fixup_implicit_builtin_block_names(spv::ExecutionModel model); | 
| 668 | 	void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model); | 
| 669 | 	bool should_force_emit_builtin_block(spv::StorageClass storage); | 
| 670 | 	void emit_push_constant_block_vulkan(const SPIRVariable &var); | 
| 671 | 	void emit_push_constant_block_glsl(const SPIRVariable &var); | 
| 672 | 	void emit_interface_block(const SPIRVariable &type); | 
| 673 | 	void emit_flattened_io_block(const SPIRVariable &var, const char *qual); | 
| 674 | 	void emit_flattened_io_block_struct(const std::string &basename, const SPIRType &type, const char *qual, | 
| 675 | 	                                    const SmallVector<uint32_t> &indices); | 
| 676 | 	void emit_flattened_io_block_member(const std::string &basename, const SPIRType &type, const char *qual, | 
| 677 | 	                                    const SmallVector<uint32_t> &indices); | 
| 678 | 	void emit_block_chain(SPIRBlock &block); | 
| 679 | 	void emit_hoisted_temporaries(SmallVector<std::pair<TypeID, ID>> &temporaries); | 
| 680 | 	std::string constant_value_macro_name(uint32_t id); | 
| 681 | 	int get_constant_mapping_to_workgroup_component(const SPIRConstant &constant) const; | 
| 682 | 	void emit_constant(const SPIRConstant &constant); | 
| 683 | 	void emit_specialization_constant_op(const SPIRConstantOp &constant); | 
| 684 | 	std::string emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block); | 
| 685 | 	bool (SPIRBlock &block, SPIRBlock::Method method); | 
| 686 |  | 
| 687 | 	void branch(BlockID from, BlockID to); | 
| 688 | 	void branch_to_continue(BlockID from, BlockID to); | 
| 689 | 	void branch(BlockID from, uint32_t cond, BlockID true_block, BlockID false_block); | 
| 690 | 	void flush_phi(BlockID from, BlockID to); | 
| 691 | 	void flush_variable_declaration(uint32_t id); | 
| 692 | 	void flush_undeclared_variables(SPIRBlock &block); | 
| 693 | 	void emit_variable_temporary_copies(const SPIRVariable &var); | 
| 694 |  | 
| 695 | 	bool should_dereference(uint32_t id); | 
| 696 | 	bool should_forward(uint32_t id) const; | 
| 697 | 	bool should_suppress_usage_tracking(uint32_t id) const; | 
| 698 | 	void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp); | 
| 699 | 	void emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op); | 
| 700 | 	void emit_emulated_ahyper_op(uint32_t result_type, uint32_t result_id, uint32_t op0, GLSLstd450 op); | 
| 701 | 	bool to_trivial_mix_op(const SPIRType &type, std::string &op, uint32_t left, uint32_t right, uint32_t lerp); | 
| 702 | 	void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, | 
| 703 | 	                             uint32_t op3, const char *op); | 
| 704 | 	void emit_trinary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, | 
| 705 | 	                          const char *op); | 
| 706 | 	void emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); | 
| 707 | 	void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); | 
| 708 | 	void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, const char *op); | 
| 709 |  | 
| 710 | 	void emit_unary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op, | 
| 711 | 	                             SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type); | 
| 712 | 	void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, | 
| 713 | 	                              SPIRType::BaseType input_type, bool skip_cast_if_equal_type); | 
| 714 | 	void emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, | 
| 715 | 	                                        const char *op, SPIRType::BaseType input_type); | 
| 716 | 	void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, | 
| 717 | 	                               const char *op, SPIRType::BaseType input_type); | 
| 718 | 	void (uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, | 
| 719 | 	                                     uint32_t op2, const char *op, SPIRType::BaseType expected_result_type, | 
| 720 | 	                                     SPIRType::BaseType input_type0, SPIRType::BaseType input_type1, | 
| 721 | 	                                     SPIRType::BaseType input_type2); | 
| 722 | 	void emit_bitfield_insert_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, | 
| 723 | 	                             uint32_t op3, const char *op, SPIRType::BaseType offset_count_type); | 
| 724 |  | 
| 725 | 	void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); | 
| 726 | 	void emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op); | 
| 727 | 	void emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); | 
| 728 | 	void emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, | 
| 729 | 	                             bool negate, SPIRType::BaseType expected_type); | 
| 730 | 	void emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, | 
| 731 | 	                         SPIRType::BaseType input_type, bool skip_cast_if_equal_type, bool implicit_integer_promotion); | 
| 732 |  | 
| 733 | 	SPIRType binary_op_bitcast_helper(std::string &cast_op0, std::string &cast_op1, SPIRType::BaseType &input_type, | 
| 734 | 	                                  uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type); | 
| 735 |  | 
| 736 | 	virtual bool emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0); | 
| 737 |  | 
| 738 | 	std::string to_ternary_expression(const SPIRType &result_type, uint32_t select, uint32_t true_value, | 
| 739 | 	                                  uint32_t false_value); | 
| 740 |  | 
| 741 | 	void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); | 
| 742 | 	void emit_unary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); | 
| 743 | 	virtual void emit_mesh_tasks(SPIRBlock &block); | 
| 744 | 	bool expression_is_forwarded(uint32_t id) const; | 
| 745 | 	bool expression_suppresses_usage_tracking(uint32_t id) const; | 
| 746 | 	bool expression_read_implies_multiple_reads(uint32_t id) const; | 
| 747 | 	SPIRExpression &emit_op(uint32_t result_type, uint32_t result_id, const std::string &rhs, bool forward_rhs, | 
| 748 | 	                        bool suppress_usage_tracking = false); | 
| 749 |  | 
| 750 | 	void access_chain_internal_append_index(std::string &expr, uint32_t base, const SPIRType *type, | 
| 751 | 	                                        AccessChainFlags flags, bool &access_chain_is_arrayed, uint32_t index); | 
| 752 |  | 
| 753 | 	std::string access_chain_internal(uint32_t base, const uint32_t *indices, uint32_t count, AccessChainFlags flags, | 
| 754 | 	                                  AccessChainMeta *meta); | 
| 755 |  | 
| 756 | 	spv::StorageClass get_expression_effective_storage_class(uint32_t ptr); | 
| 757 | 	virtual bool access_chain_needs_stage_io_builtin_translation(uint32_t base); | 
| 758 |  | 
| 759 | 	virtual void check_physical_type_cast(std::string &expr, const SPIRType *type, uint32_t physical_type); | 
| 760 | 	virtual bool prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, | 
| 761 | 	                                                    spv::StorageClass storage, bool &is_packed); | 
| 762 |  | 
| 763 | 	std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, | 
| 764 | 	                         AccessChainMeta *meta = nullptr, bool ptr_chain = false); | 
| 765 |  | 
| 766 | 	std::string flattened_access_chain(uint32_t base, const uint32_t *indices, uint32_t count, | 
| 767 | 	                                   const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride, | 
| 768 | 	                                   uint32_t array_stride, bool need_transpose); | 
| 769 | 	std::string flattened_access_chain_struct(uint32_t base, const uint32_t *indices, uint32_t count, | 
| 770 | 	                                          const SPIRType &target_type, uint32_t offset); | 
| 771 | 	std::string flattened_access_chain_matrix(uint32_t base, const uint32_t *indices, uint32_t count, | 
| 772 | 	                                          const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride, | 
| 773 | 	                                          bool need_transpose); | 
| 774 | 	std::string flattened_access_chain_vector(uint32_t base, const uint32_t *indices, uint32_t count, | 
| 775 | 	                                          const SPIRType &target_type, uint32_t offset, uint32_t matrix_stride, | 
| 776 | 	                                          bool need_transpose); | 
| 777 | 	std::pair<std::string, uint32_t> flattened_access_chain_offset(const SPIRType &basetype, const uint32_t *indices, | 
| 778 | 	                                                               uint32_t count, uint32_t offset, | 
| 779 | 	                                                               uint32_t word_stride, bool *need_transpose = nullptr, | 
| 780 | 	                                                               uint32_t *matrix_stride = nullptr, | 
| 781 | 	                                                               uint32_t *array_stride = nullptr, | 
| 782 | 	                                                               bool ptr_chain = false); | 
| 783 |  | 
| 784 | 	const char *index_to_swizzle(uint32_t index); | 
| 785 | 	std::string remap_swizzle(const SPIRType &result_type, uint32_t input_components, const std::string &expr); | 
| 786 | 	std::string declare_temporary(uint32_t type, uint32_t id); | 
| 787 | 	void emit_uninitialized_temporary(uint32_t type, uint32_t id); | 
| 788 | 	SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id); | 
| 789 | 	void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist); | 
| 790 | 	std::string to_non_uniform_aware_expression(uint32_t id); | 
| 791 | 	std::string to_expression(uint32_t id, bool register_expression_read = true); | 
| 792 | 	std::string to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type); | 
| 793 | 	std::string to_rerolled_array_expression(const SPIRType &parent_type, const std::string &expr, const SPIRType &type); | 
| 794 | 	std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true); | 
| 795 | 	std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true); | 
| 796 | 	std::string to_unpacked_row_major_matrix_expression(uint32_t id); | 
| 797 | 	std::string to_enclosed_unpacked_expression(uint32_t id, bool register_expression_read = true); | 
| 798 | 	std::string to_dereferenced_expression(uint32_t id, bool register_expression_read = true); | 
| 799 | 	std::string to_pointer_expression(uint32_t id, bool register_expression_read = true); | 
| 800 | 	std::string to_enclosed_pointer_expression(uint32_t id, bool register_expression_read = true); | 
| 801 | 	std::string (uint32_t id, uint32_t index); | 
| 802 | 	std::string (uint32_t result_type, const SPIRConstant &c, | 
| 803 | 	                                                     const uint32_t *chain, uint32_t length); | 
| 804 | 	static bool needs_enclose_expression(const std::string &expr); | 
| 805 | 	std::string enclose_expression(const std::string &expr); | 
| 806 | 	std::string dereference_expression(const SPIRType &expression_type, const std::string &expr); | 
| 807 | 	std::string address_of_expression(const std::string &expr); | 
| 808 | 	void strip_enclosed_expression(std::string &expr); | 
| 809 | 	std::string to_member_name(const SPIRType &type, uint32_t index); | 
| 810 | 	virtual std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain_is_resolved); | 
| 811 | 	std::string to_multi_member_reference(const SPIRType &type, const SmallVector<uint32_t> &indices); | 
| 812 | 	std::string type_to_glsl_constructor(const SPIRType &type); | 
| 813 | 	std::string argument_decl(const SPIRFunction::Parameter &arg); | 
| 814 | 	virtual std::string to_qualifiers_glsl(uint32_t id); | 
| 815 | 	void fixup_io_block_patch_primitive_qualifiers(const SPIRVariable &var); | 
| 816 | 	void emit_output_variable_initializer(const SPIRVariable &var); | 
| 817 | 	std::string to_precision_qualifiers_glsl(uint32_t id); | 
| 818 | 	virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var); | 
| 819 | 	std::string flags_to_qualifiers_glsl(const SPIRType &type, const Bitset &flags); | 
| 820 | 	const char *format_to_glsl(spv::ImageFormat format); | 
| 821 | 	virtual std::string layout_for_member(const SPIRType &type, uint32_t index); | 
| 822 | 	virtual std::string to_interpolation_qualifiers(const Bitset &flags); | 
| 823 | 	std::string layout_for_variable(const SPIRVariable &variable); | 
| 824 | 	std::string to_combined_image_sampler(VariableID image_id, VariableID samp_id); | 
| 825 | 	virtual bool skip_argument(uint32_t id) const; | 
| 826 | 	virtual bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, | 
| 827 | 	                             spv::StorageClass lhs_storage, spv::StorageClass rhs_storage); | 
| 828 | 	virtual void emit_block_hints(const SPIRBlock &block); | 
| 829 | 	virtual std::string to_initializer_expression(const SPIRVariable &var); | 
| 830 | 	virtual std::string to_zero_initialized_expression(uint32_t type_id); | 
| 831 | 	bool type_can_zero_initialize(const SPIRType &type) const; | 
| 832 |  | 
| 833 | 	bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing, | 
| 834 | 	                                uint32_t *failed_index = nullptr, uint32_t start_offset = 0, | 
| 835 | 	                                uint32_t end_offset = ~(0u)); | 
| 836 | 	std::string buffer_to_packing_standard(const SPIRType &type, | 
| 837 | 	                                       bool support_std430_without_scalar_layout, | 
| 838 | 	                                       bool support_enhanced_layouts); | 
| 839 |  | 
| 840 | 	uint32_t type_to_packed_base_size(const SPIRType &type, BufferPackingStandard packing); | 
| 841 | 	uint32_t type_to_packed_alignment(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing); | 
| 842 | 	uint32_t type_to_packed_array_stride(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing); | 
| 843 | 	uint32_t type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing); | 
| 844 | 	uint32_t type_to_location_count(const SPIRType &type) const; | 
| 845 |  | 
| 846 | 	std::string bitcast_glsl(const SPIRType &result_type, uint32_t arg); | 
| 847 | 	virtual std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type); | 
| 848 |  | 
| 849 | 	std::string bitcast_expression(SPIRType::BaseType target_type, uint32_t arg); | 
| 850 | 	std::string bitcast_expression(const SPIRType &target_type, SPIRType::BaseType expr_type, const std::string &expr); | 
| 851 |  | 
| 852 | 	std::string build_composite_combiner(uint32_t result_type, const uint32_t *elems, uint32_t length); | 
| 853 | 	bool remove_duplicate_swizzle(std::string &op); | 
| 854 | 	bool remove_unity_swizzle(uint32_t base, std::string &op); | 
| 855 |  | 
| 856 | 	// Can modify flags to remote readonly/writeonly if image type | 
| 857 | 	// and force recompile. | 
| 858 | 	bool check_atomic_image(uint32_t id); | 
| 859 |  | 
| 860 | 	virtual void replace_illegal_names(); | 
| 861 | 	void replace_illegal_names(const std::unordered_set<std::string> &keywords); | 
| 862 | 	virtual void emit_entry_point_declarations(); | 
| 863 |  | 
| 864 | 	void replace_fragment_output(SPIRVariable &var); | 
| 865 | 	void replace_fragment_outputs(); | 
| 866 | 	std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t id); | 
| 867 |  | 
| 868 | 	void forward_relaxed_precision(uint32_t dst_id, const uint32_t *args, uint32_t length); | 
| 869 | 	void analyze_precision_requirements(uint32_t type_id, uint32_t dst_id, uint32_t *args, uint32_t length); | 
| 870 | 	Options::Precision analyze_expression_precision(const uint32_t *args, uint32_t length) const; | 
| 871 |  | 
| 872 | 	uint32_t indent = 0; | 
| 873 |  | 
| 874 | 	std::unordered_set<uint32_t> emitted_functions; | 
| 875 |  | 
| 876 | 	// Ensure that we declare phi-variable copies even if the original declaration isn't deferred | 
| 877 | 	std::unordered_set<uint32_t> flushed_phi_variables; | 
| 878 |  | 
| 879 | 	std::unordered_set<uint32_t> flattened_buffer_blocks; | 
| 880 | 	std::unordered_map<uint32_t, bool> flattened_structs; | 
| 881 |  | 
| 882 | 	ShaderSubgroupSupportHelper shader_subgroup_supporter; | 
| 883 |  | 
| 884 | 	std::string load_flattened_struct(const std::string &basename, const SPIRType &type); | 
| 885 | 	std::string to_flattened_struct_member(const std::string &basename, const SPIRType &type, uint32_t index); | 
| 886 | 	void store_flattened_struct(uint32_t lhs_id, uint32_t value); | 
| 887 | 	void store_flattened_struct(const std::string &basename, uint32_t rhs, const SPIRType &type, | 
| 888 | 	                            const SmallVector<uint32_t> &indices); | 
| 889 | 	std::string to_flattened_access_chain_expression(uint32_t id); | 
| 890 |  | 
| 891 | 	// Usage tracking. If a temporary is used more than once, use the temporary instead to | 
| 892 | 	// avoid AST explosion when SPIRV is generated with pure SSA and doesn't write stuff to variables. | 
| 893 | 	std::unordered_map<uint32_t, uint32_t> expression_usage_counts; | 
| 894 | 	void track_expression_read(uint32_t id); | 
| 895 |  | 
| 896 | 	SmallVector<std::string> forced_extensions; | 
| 897 | 	SmallVector<std::string> ; | 
| 898 |  | 
| 899 | 	// Used when expressions emit extra opcodes with their own unique IDs, | 
| 900 | 	// and we need to reuse the IDs across recompilation loops. | 
| 901 | 	// Currently used by NMin/Max/Clamp implementations. | 
| 902 | 	std::unordered_map<uint32_t, uint32_t> ; | 
| 903 |  | 
| 904 | 	SmallVector<TypeID> workaround_ubo_load_overload_types; | 
| 905 | 	void request_workaround_wrapper_overload(TypeID id); | 
| 906 | 	void rewrite_load_for_wrapped_row_major(std::string &expr, TypeID loaded_type, ID ptr); | 
| 907 |  | 
| 908 | 	uint32_t statement_count = 0; | 
| 909 |  | 
| 910 | 	inline bool is_legacy() const | 
| 911 | 	{ | 
| 912 | 		return (options.es && options.version < 300) || (!options.es && options.version < 130); | 
| 913 | 	} | 
| 914 |  | 
| 915 | 	inline bool is_legacy_es() const | 
| 916 | 	{ | 
| 917 | 		return options.es && options.version < 300; | 
| 918 | 	} | 
| 919 |  | 
| 920 | 	inline bool is_legacy_desktop() const | 
| 921 | 	{ | 
| 922 | 		return !options.es && options.version < 130; | 
| 923 | 	} | 
| 924 |  | 
| 925 | 	enum Polyfill : uint32_t | 
| 926 | 	{ | 
| 927 | 		PolyfillTranspose2x2 = 1 << 0, | 
| 928 | 		PolyfillTranspose3x3 = 1 << 1, | 
| 929 | 		PolyfillTranspose4x4 = 1 << 2, | 
| 930 | 		PolyfillDeterminant2x2 = 1 << 3, | 
| 931 | 		PolyfillDeterminant3x3 = 1 << 4, | 
| 932 | 		PolyfillDeterminant4x4 = 1 << 5, | 
| 933 | 		PolyfillMatrixInverse2x2 = 1 << 6, | 
| 934 | 		PolyfillMatrixInverse3x3 = 1 << 7, | 
| 935 | 		PolyfillMatrixInverse4x4 = 1 << 8, | 
| 936 | 		PolyfillNMin16 = 1 << 9, | 
| 937 | 		PolyfillNMin32 = 1 << 10, | 
| 938 | 		PolyfillNMin64 = 1 << 11, | 
| 939 | 		PolyfillNMax16 = 1 << 12, | 
| 940 | 		PolyfillNMax32 = 1 << 13, | 
| 941 | 		PolyfillNMax64 = 1 << 14, | 
| 942 | 		PolyfillNClamp16 = 1 << 15, | 
| 943 | 		PolyfillNClamp32 = 1 << 16, | 
| 944 | 		PolyfillNClamp64 = 1 << 17, | 
| 945 | 	}; | 
| 946 |  | 
| 947 | 	uint32_t required_polyfills = 0; | 
| 948 | 	uint32_t required_polyfills_relaxed = 0; | 
| 949 | 	void require_polyfill(Polyfill polyfill, bool relaxed); | 
| 950 |  | 
| 951 | 	bool ray_tracing_is_khr = false; | 
| 952 | 	bool barycentric_is_nv = false; | 
| 953 | 	void ray_tracing_khr_fixup_locations(); | 
| 954 |  | 
| 955 | 	bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure); | 
| 956 | 	void register_call_out_argument(uint32_t id); | 
| 957 | 	void register_impure_function_call(); | 
| 958 | 	void register_control_dependent_expression(uint32_t expr); | 
| 959 |  | 
| 960 | 	// GL_EXT_shader_pixel_local_storage support. | 
| 961 | 	std::vector<PlsRemap> pls_inputs; | 
| 962 | 	std::vector<PlsRemap> pls_outputs; | 
| 963 | 	std::string pls_decl(const PlsRemap &variable); | 
| 964 | 	const char *to_pls_qualifiers_glsl(const SPIRVariable &variable); | 
| 965 | 	void emit_pls(); | 
| 966 | 	void remap_pls_variables(); | 
| 967 |  | 
| 968 | 	// GL_EXT_shader_framebuffer_fetch support. | 
| 969 | 	std::vector<std::pair<uint32_t, uint32_t>> subpass_to_framebuffer_fetch_attachment; | 
| 970 | 	std::vector<std::pair<uint32_t, bool>> inout_color_attachments; | 
| 971 | 	bool location_is_framebuffer_fetch(uint32_t location) const; | 
| 972 | 	bool location_is_non_coherent_framebuffer_fetch(uint32_t location) const; | 
| 973 | 	bool subpass_input_is_framebuffer_fetch(uint32_t id) const; | 
| 974 | 	void emit_inout_fragment_outputs_copy_to_subpass_inputs(); | 
| 975 | 	const SPIRVariable *find_subpass_input_by_attachment_index(uint32_t index) const; | 
| 976 | 	const SPIRVariable *find_color_output_by_location(uint32_t location) const; | 
| 977 |  | 
| 978 | 	// A variant which takes two sets of name. The secondary is only used to verify there are no collisions, | 
| 979 | 	// but the set is not updated when we have found a new name. | 
| 980 | 	// Used primarily when adding block interface names. | 
| 981 | 	void add_variable(std::unordered_set<std::string> &variables_primary, | 
| 982 | 	                  const std::unordered_set<std::string> &variables_secondary, std::string &name); | 
| 983 |  | 
| 984 | 	void check_function_call_constraints(const uint32_t *args, uint32_t length); | 
| 985 | 	void handle_invalid_expression(uint32_t id); | 
| 986 | 	void force_temporary_and_recompile(uint32_t id); | 
| 987 | 	void find_static_extensions(); | 
| 988 |  | 
| 989 | 	uint32_t consume_temporary_in_precision_context(uint32_t type_id, uint32_t id, Options::Precision precision); | 
| 990 | 	std::unordered_map<uint32_t, uint32_t> temporary_to_mirror_precision_alias; | 
| 991 | 	std::unordered_set<uint32_t> composite_insert_overwritten; | 
| 992 | 	std::unordered_set<uint32_t> block_composite_insert_overwrite; | 
| 993 |  | 
| 994 | 	std::string emit_for_loop_initializers(const SPIRBlock &block); | 
| 995 | 	void emit_while_loop_initializers(const SPIRBlock &block); | 
| 996 | 	bool for_loop_initializers_are_same_type(const SPIRBlock &block); | 
| 997 | 	bool optimize_read_modify_write(const SPIRType &type, const std::string &lhs, const std::string &rhs); | 
| 998 | 	void fixup_image_load_store_access(); | 
| 999 |  | 
| 1000 | 	bool type_is_empty(const SPIRType &type); | 
| 1001 |  | 
| 1002 | 	bool can_use_io_location(spv::StorageClass storage, bool block); | 
| 1003 | 	const Instruction *get_next_instruction_in_block(const Instruction &instr); | 
| 1004 | 	static uint32_t mask_relevant_memory_semantics(uint32_t semantics); | 
| 1005 |  | 
| 1006 | 	std::string convert_half_to_string(const SPIRConstant &value, uint32_t col, uint32_t row); | 
| 1007 | 	std::string convert_float_to_string(const SPIRConstant &value, uint32_t col, uint32_t row); | 
| 1008 | 	std::string convert_double_to_string(const SPIRConstant &value, uint32_t col, uint32_t row); | 
| 1009 |  | 
| 1010 | 	std::string convert_separate_image_to_expression(uint32_t id); | 
| 1011 |  | 
| 1012 | 	// Builtins in GLSL are always specific signedness, but the SPIR-V can declare them | 
| 1013 | 	// as either unsigned or signed. | 
| 1014 | 	// Sometimes we will need to automatically perform casts on load and store to make this work. | 
| 1015 | 	virtual SPIRType::BaseType get_builtin_basetype(spv::BuiltIn builtin, SPIRType::BaseType default_type); | 
| 1016 | 	virtual void cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type); | 
| 1017 | 	virtual void cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type); | 
| 1018 | 	void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr); | 
| 1019 | 	bool unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id); | 
| 1020 | 	void convert_non_uniform_expression(std::string &expr, uint32_t ptr_id); | 
| 1021 |  | 
| 1022 | 	void handle_store_to_invariant_variable(uint32_t store_id, uint32_t value_id); | 
| 1023 | 	void disallow_forwarding_in_expression_chain(const SPIRExpression &expr); | 
| 1024 |  | 
| 1025 | 	bool expression_is_constant_null(uint32_t id) const; | 
| 1026 | 	bool expression_is_non_value_type_array(uint32_t ptr); | 
| 1027 | 	virtual void emit_store_statement(uint32_t lhs_expression, uint32_t rhs_expression); | 
| 1028 |  | 
| 1029 | 	uint32_t get_integer_width_for_instruction(const Instruction &instr) const; | 
| 1030 | 	uint32_t get_integer_width_for_glsl_instruction(GLSLstd450 op, const uint32_t *arguments, uint32_t length) const; | 
| 1031 |  | 
| 1032 | 	bool variable_is_lut(const SPIRVariable &var) const; | 
| 1033 |  | 
| 1034 | 	char current_locale_radix_character = '.'; | 
| 1035 |  | 
| 1036 | 	void fixup_type_alias(); | 
| 1037 | 	void reorder_type_alias(); | 
| 1038 | 	void fixup_anonymous_struct_names(); | 
| 1039 | 	void fixup_anonymous_struct_names(std::unordered_set<uint32_t> &visited, const SPIRType &type); | 
| 1040 |  | 
| 1041 | 	static const char *vector_swizzle(int vecsize, int index); | 
| 1042 |  | 
| 1043 | 	bool is_stage_output_location_masked(uint32_t location, uint32_t component) const; | 
| 1044 | 	bool is_stage_output_builtin_masked(spv::BuiltIn builtin) const; | 
| 1045 | 	bool is_stage_output_variable_masked(const SPIRVariable &var) const; | 
| 1046 | 	bool is_stage_output_block_member_masked(const SPIRVariable &var, uint32_t index, bool strip_array) const; | 
| 1047 | 	bool is_per_primitive_variable(const SPIRVariable &var) const; | 
| 1048 | 	uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const; | 
| 1049 | 	uint32_t get_declared_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const; | 
| 1050 | 	std::unordered_set<LocationComponentPair, InternalHasher> masked_output_locations; | 
| 1051 | 	std::unordered_set<uint32_t> masked_output_builtins; | 
| 1052 |  | 
| 1053 | 	FloatFormatter *float_formatter = nullptr; | 
| 1054 | 	std::string format_float(float value) const; | 
| 1055 | 	std::string format_double(double value) const; | 
| 1056 |  | 
| 1057 | private: | 
| 1058 | 	void init(); | 
| 1059 |  | 
| 1060 | 	SmallVector<ConstantID> get_composite_constant_ids(ConstantID const_id); | 
| 1061 | 	void fill_composite_constant(SPIRConstant &constant, TypeID type_id, const SmallVector<ConstantID> &initializers); | 
| 1062 | 	void set_composite_constant(ConstantID const_id, TypeID type_id, const SmallVector<ConstantID> &initializers); | 
| 1063 | 	TypeID get_composite_member_type(TypeID type_id, uint32_t member_idx); | 
| 1064 | 	std::unordered_map<uint32_t, SmallVector<ConstantID>> const_composite_insert_ids; | 
| 1065 | }; | 
| 1066 | } // namespace SPIRV_CROSS_NAMESPACE | 
| 1067 |  | 
| 1068 | #endif | 
| 1069 |  |