effect_codegen_glsl.cpp (65805B)
1 /* 2 * Copyright (C) 2014 Patrick Mours 3 * SPDX-License-Identifier: BSD-3-Clause 4 */ 5 6 #include "effect_parser.hpp" 7 #include "effect_codegen.hpp" 8 #include <cmath> // signbit, isinf, isnan 9 #include <cstdio> // snprintf 10 #include <cassert> 11 #include <algorithm> // std::find_if, std::max 12 #include <locale> 13 #include <sstream> 14 #include <unordered_set> 15 16 using namespace reshadefx; 17 18 namespace { 19 class codegen_glsl final : public codegen 20 { 21 public: 22 codegen_glsl(bool gles, bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types, bool flip_vert_y) 23 : _gles(gles), _debug_info(debug_info), _vulkan_semantics(vulkan_semantics), _uniforms_to_spec_constants(uniforms_to_spec_constants), _enable_16bit_types(enable_16bit_types), _flip_vert_y(flip_vert_y) 24 { 25 // Create default block and reserve a memory block to avoid frequent reallocations 26 std::string &block = _blocks.emplace(0, std::string()).first->second; 27 block.reserve(8192); 28 } 29 30 private: 31 enum class naming 32 { 33 // After escaping, name should already be unique, so no additional steps are taken 34 unique, 35 // After escaping, will be numbered when clashing with another name 36 general, 37 // This is a special name that is not modified and should be unique 38 reserved, 39 // Replace name with a code snippet 40 expression, 41 }; 42 43 std::string _ubo_block; 44 std::string _compute_block; 45 std::unordered_map<id, std::string> _names; 46 std::unordered_map<id, std::string> _blocks; 47 bool _gles = false; 48 bool _debug_info = false; 49 bool _vulkan_semantics = false; 50 bool _uniforms_to_spec_constants = false; 51 bool _enable_16bit_types = false; 52 bool _flip_vert_y = false; 53 bool _enable_control_flow_attributes = false; 54 std::unordered_map<id, id> _remapped_sampler_variables; 55 std::unordered_map<std::string, uint32_t> _semantic_to_location; 56 57 // Only write compatibility intrinsics to result if they are actually in use 58 bool _uses_fmod = false; 59 bool _uses_componentwise_or = false; 60 bool _uses_componentwise_and = false; 61 bool _uses_componentwise_cond = false; 62 63 void write_result(module &module) override 64 { 65 module = std::move(_module); 66 67 std::string preamble; 68 69 if (_enable_16bit_types) 70 // GL_NV_gpu_shader5, GL_AMD_gpu_shader_half_float or GL_EXT_shader_16bit_storage 71 preamble += "#extension GL_NV_gpu_shader5 : require\n"; 72 if (_enable_control_flow_attributes) 73 preamble += "#extension GL_EXT_control_flow_attributes : enable\n"; 74 75 if (_uses_fmod) 76 preamble += "float fmodHLSL(float x, float y) { return x - y * trunc(x / y); }\n" 77 "vec2 fmodHLSL(vec2 x, vec2 y) { return x - y * trunc(x / y); }\n" 78 "vec3 fmodHLSL(vec3 x, vec3 y) { return x - y * trunc(x / y); }\n" 79 "vec4 fmodHLSL(vec4 x, vec4 y) { return x - y * trunc(x / y); }\n" 80 "mat2 fmodHLSL(mat2 x, mat2 y) { return x - matrixCompMult(y, mat2(trunc(x[0] / y[0]), trunc(x[1] / y[1]))); }\n" 81 "mat3 fmodHLSL(mat3 x, mat3 y) { return x - matrixCompMult(y, mat3(trunc(x[0] / y[0]), trunc(x[1] / y[1]), trunc(x[2] / y[2]))); }\n" 82 "mat4 fmodHLSL(mat4 x, mat4 y) { return x - matrixCompMult(y, mat4(trunc(x[0] / y[0]), trunc(x[1] / y[1]), trunc(x[2] / y[2]), trunc(x[3] / y[3]))); }\n"; 83 if (_uses_componentwise_or) 84 preamble += 85 "bvec2 compOr(bvec2 a, bvec2 b) { return bvec2(a.x || b.x, a.y || b.y); }\n" 86 "bvec3 compOr(bvec3 a, bvec3 b) { return bvec3(a.x || b.x, a.y || b.y, a.z || b.z); }\n" 87 "bvec4 compOr(bvec4 a, bvec4 b) { return bvec4(a.x || b.x, a.y || b.y, a.z || b.z, a.w || b.w); }\n"; 88 if (_uses_componentwise_and) 89 preamble += 90 "bvec2 compAnd(bvec2 a, bvec2 b) { return bvec2(a.x && b.x, a.y && b.y); }\n" 91 "bvec3 compAnd(bvec3 a, bvec3 b) { return bvec3(a.x && b.x, a.y && b.y, a.z && b.z); }\n" 92 "bvec4 compAnd(bvec4 a, bvec4 b) { return bvec4(a.x && b.x, a.y && b.y, a.z && b.z, a.w && b.w); }\n"; 93 if (_uses_componentwise_cond) 94 preamble += 95 "vec2 compCond(bvec2 cond, vec2 a, vec2 b) { return vec2(cond.x ? a.x : b.x, cond.y ? a.y : b.y); }\n" 96 "vec3 compCond(bvec3 cond, vec3 a, vec3 b) { return vec3(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z); }\n" 97 "vec4 compCond(bvec4 cond, vec4 a, vec4 b) { return vec4(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z, cond.w ? a.w : b.w); }\n" 98 "ivec2 compCond(bvec2 cond, ivec2 a, ivec2 b) { return ivec2(cond.x ? a.x : b.x, cond.y ? a.y : b.y); }\n" 99 "ivec3 compCond(bvec3 cond, ivec3 a, ivec3 b) { return ivec3(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z); }\n" 100 "ivec4 compCond(bvec4 cond, ivec4 a, ivec4 b) { return ivec4(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z, cond.w ? a.w : b.w); }\n" 101 "uvec2 compCond(bvec2 cond, uvec2 a, uvec2 b) { return uvec2(cond.x ? a.x : b.x, cond.y ? a.y : b.y); }\n" 102 "uvec3 compCond(bvec3 cond, uvec3 a, uvec3 b) { return uvec3(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z); }\n" 103 "uvec4 compCond(bvec4 cond, uvec4 a, uvec4 b) { return uvec4(cond.x ? a.x : b.x, cond.y ? a.y : b.y, cond.z ? a.z : b.z, cond.w ? a.w : b.w); }\n"; 104 105 if (!_ubo_block.empty()) 106 { 107 if (_vulkan_semantics) 108 { 109 preamble += "layout(std140, set = 0, binding = 0) uniform _Globals {\n" + _ubo_block + "};\n"; 110 } 111 else 112 { 113 preamble += "layout(std140, binding = 0) uniform _Globals {\n" + _ubo_block + "};\n"; 114 } 115 } 116 117 module.code.assign(preamble.begin(), preamble.end()); 118 119 const std::string &main_block = _blocks.at(0); 120 module.code.insert(module.code.end(), main_block.begin(), main_block.end()); 121 } 122 123 template <bool is_param = false, bool is_decl = true, bool is_interface = false> 124 void write_type(std::string &s, const type &type) const 125 { 126 if constexpr (is_decl) 127 { 128 // Global variables are implicitly 'static' in GLSL, so the keyword does not exist 129 if (type.has(type::q_precise)) 130 s += "precise "; 131 if (type.has(type::q_groupshared)) 132 s += "shared "; 133 } 134 135 if constexpr (is_interface) 136 { 137 if (type.has(type::q_linear)) 138 s += "smooth "; 139 if (type.has(type::q_noperspective)) 140 s += "noperspective "; 141 if (type.has(type::q_centroid)) 142 s += "centroid "; 143 if (type.has(type::q_nointerpolation)) 144 s += "flat "; 145 } 146 147 if constexpr (is_interface || is_param) 148 { 149 if (type.has(type::q_inout)) 150 s += "inout "; 151 else if (type.has(type::q_in)) 152 s += "in "; 153 else if (type.has(type::q_out)) 154 s += "out "; 155 } 156 157 switch (type.base) 158 { 159 case type::t_void: 160 s += "void"; 161 break; 162 case type::t_bool: 163 if (type.cols > 1) 164 s += "mat" + std::to_string(type.rows) + 'x' + std::to_string(type.cols); 165 else if (type.rows > 1) 166 s += "bvec" + std::to_string(type.rows); 167 else 168 s += "bool"; 169 break; 170 case type::t_min16int: 171 if (_enable_16bit_types) 172 { 173 assert(type.cols == 1); 174 if (type.rows > 1) 175 s += "i16vec" + std::to_string(type.rows); 176 else 177 s += "int16_t"; 178 break; 179 } 180 else if constexpr (is_decl) 181 s += "mediump "; 182 [[fallthrough]]; 183 case type::t_int: 184 if (type.cols > 1) 185 s += "mat" + std::to_string(type.rows) + 'x' + std::to_string(type.cols); 186 else if (type.rows > 1) 187 s += "ivec" + std::to_string(type.rows); 188 else 189 s += "int"; 190 break; 191 case type::t_min16uint: 192 if (_enable_16bit_types) 193 { 194 assert(type.cols == 1); 195 if (type.rows > 1) 196 s += "u16vec" + std::to_string(type.rows); 197 else 198 s += "uint16_t"; 199 break; 200 } 201 else if constexpr (is_decl) 202 s += "mediump "; 203 [[fallthrough]]; 204 case type::t_uint: 205 if (type.cols > 1) 206 s += "mat" + std::to_string(type.rows) + 'x' + std::to_string(type.cols); 207 else if (type.rows > 1) 208 s += "uvec" + std::to_string(type.rows); 209 else 210 s += "uint"; 211 break; 212 case type::t_min16float: 213 if (_enable_16bit_types) 214 { 215 assert(type.cols == 1); 216 if (type.rows > 1) 217 s += "f16vec" + std::to_string(type.rows); 218 else 219 s += "float16_t"; 220 break; 221 } 222 else if constexpr (is_decl) 223 s += "mediump "; 224 [[fallthrough]]; 225 case type::t_float: 226 if (type.cols > 1) 227 s += "mat" + std::to_string(type.rows) + 'x' + std::to_string(type.cols); 228 else if (type.rows > 1) 229 s += "vec" + std::to_string(type.rows); 230 else 231 s += "float"; 232 break; 233 case type::t_struct: 234 s += id_to_name(type.definition); 235 break; 236 case type::t_sampler1d_int: 237 s += "isampler1D"; 238 break; 239 case type::t_sampler2d_int: 240 s += "isampler2D"; 241 break; 242 case type::t_sampler3d_int: 243 s += "isampler3D"; 244 break; 245 case type::t_sampler1d_uint: 246 s += "usampler1D"; 247 break; 248 case type::t_sampler3d_uint: 249 s += "usampler3D"; 250 break; 251 case type::t_sampler2d_uint: 252 s += "usampler2D"; 253 break; 254 case type::t_sampler1d_float: 255 s += "sampler1D"; 256 break; 257 case type::t_sampler2d_float: 258 s += "sampler2D"; 259 break; 260 case type::t_sampler3d_float: 261 s += "sampler3D"; 262 break; 263 case type::t_storage1d_int: 264 if constexpr (is_param) 265 s += "writeonly "; 266 s += "iimage1D"; 267 break; 268 case type::t_storage2d_int: 269 if constexpr (is_param) 270 s += "writeonly "; 271 s += "iimage2D"; 272 break; 273 case type::t_storage3d_int: 274 if constexpr (is_param) 275 s += "writeonly "; 276 s += "iimage3D"; 277 break; 278 case type::t_storage1d_uint: 279 if constexpr (is_param) 280 s += "writeonly "; 281 s += "uimage1D"; 282 break; 283 case type::t_storage2d_uint: 284 if constexpr (is_param) 285 s += "writeonly "; 286 s += "uimage2D"; 287 break; 288 case type::t_storage3d_uint: 289 if constexpr (is_param) 290 s += "writeonly "; 291 s += "uimage3D"; 292 break; 293 case type::t_storage1d_float: 294 if constexpr (is_param) 295 s += "writeonly "; 296 s += "image1D"; 297 break; 298 case type::t_storage2d_float: 299 if constexpr (is_param) // Images need a format to be readable, but declaring that on function parameters is not well supported, so can only support write-only images there 300 s += "writeonly "; 301 s += "image2D"; 302 break; 303 case type::t_storage3d_float: 304 if constexpr (is_param) 305 s += "writeonly "; 306 s += "image3D"; 307 break; 308 default: 309 assert(false); 310 } 311 } 312 void write_constant(std::string &s, const type &type, const constant &data) const 313 { 314 if (type.is_array()) 315 { 316 auto elem_type = type; 317 elem_type.array_length = 0; 318 319 write_type<false, false>(s, elem_type); 320 s += '[' + std::to_string(type.array_length) + "]("; 321 322 for (int i = 0; i < type.array_length; ++i) 323 { 324 write_constant(s, elem_type, i < static_cast<int>(data.array_data.size()) ? data.array_data[i] : constant()); 325 326 if (i < type.array_length - 1) 327 s += ", "; 328 } 329 330 s += ')'; 331 return; 332 } 333 334 // There can only be numeric constants 335 assert(type.is_numeric()); 336 337 if (!type.is_scalar()) 338 write_type<false, false>(s, type), s += '('; 339 340 for (unsigned int i = 0, components = type.components(); i < components; ++i) 341 { 342 switch (type.base) 343 { 344 case type::t_bool: 345 s += data.as_uint[i] ? "true" : "false"; 346 break; 347 case type::t_min16int: 348 case type::t_int: 349 s += std::to_string(data.as_int[i]); 350 break; 351 case type::t_min16uint: 352 case type::t_uint: 353 s += std::to_string(data.as_uint[i]) + 'u'; 354 break; 355 case type::t_min16float: 356 case type::t_float: 357 if (std::isnan(data.as_float[i])) { 358 s += "0.0/0.0/*nan*/"; 359 break; 360 } 361 if (std::isinf(data.as_float[i])) { 362 s += std::signbit(data.as_float[i]) ? "1.0/0.0/*inf*/" : "-1.0/0.0/*-inf*/"; 363 break; 364 } 365 { 366 std::ostringstream ss; 367 ss.imbue(std::locale::classic()); 368 ss << data.as_float[i]; 369 s += ss.str(); 370 } 371 break; 372 default: 373 assert(false); 374 } 375 376 if (i < components - 1) 377 s += ", "; 378 } 379 380 if (!type.is_scalar()) 381 s += ')'; 382 } 383 void write_location(std::string &s, const location &loc) const 384 { 385 if (loc.source.empty() || !_debug_info) 386 return; 387 388 s += "#line " + std::to_string(loc.line) + '\n'; 389 } 390 void write_texture_format(std::string &s, texture_format format) 391 { 392 switch (format) 393 { 394 case texture_format::r8: 395 s += "r8"; 396 break; 397 case texture_format::r16: 398 s += "r16"; 399 break; 400 case texture_format::r16f: 401 s += "r16f"; 402 break; 403 case texture_format::r32i: 404 s += "r32i"; 405 break; 406 case texture_format::r32u: 407 s += "r32u"; 408 break; 409 case texture_format::r32f: 410 s += "r32f"; 411 break; 412 case texture_format::rg8: 413 s += "rg8"; 414 break; 415 case texture_format::rg16: 416 s += "rg16"; 417 break; 418 case texture_format::rg16f: 419 s += "rg16f"; 420 break; 421 case texture_format::rg32f: 422 s += "rg32f"; 423 break; 424 case texture_format::rgba8: 425 s += "rgba8"; 426 break; 427 case texture_format::rgba16: 428 s += "rgba16"; 429 break; 430 case texture_format::rgba16f: 431 s += "rgba16f"; 432 break; 433 case texture_format::rgba32f: 434 s += "rgba32f"; 435 break; 436 case texture_format::rgb10a2: 437 s += "rgb10_a2"; 438 break; 439 default: 440 assert(false); 441 } 442 } 443 444 std::string id_to_name(id id) const 445 { 446 if (const auto it = _remapped_sampler_variables.find(id); 447 it != _remapped_sampler_variables.end()) 448 id = it->second; 449 450 assert(id != 0); 451 if (const auto names_it = _names.find(id); 452 names_it != _names.end()) 453 return names_it->second; 454 return '_' + std::to_string(id); 455 } 456 457 template <naming naming_type = naming::general> 458 void define_name(const id id, std::string name) 459 { 460 assert(!name.empty()); 461 if constexpr (naming_type != naming::expression) 462 if (name[0] == '_') 463 return; // Filter out names that may clash with automatic ones 464 if constexpr (naming_type != naming::reserved) 465 name = escape_name(std::move(name)); 466 if constexpr (naming_type == naming::general) 467 if (std::find_if(_names.begin(), _names.end(), [&name](const auto &it) { return it.second == name; }) != _names.end()) 468 name += '_' + std::to_string(id); // Append a numbered suffix if the name already exists 469 _names[id] = std::move(name); 470 } 471 472 uint32_t semantic_to_location(const std::string &semantic, uint32_t max_array_length = 1) 473 { 474 if (semantic.compare(0, 5, "COLOR") == 0) 475 return std::strtoul(semantic.c_str() + 5, nullptr, 10); 476 if (semantic.compare(0, 9, "SV_TARGET") == 0) 477 return std::strtoul(semantic.c_str() + 9, nullptr, 10); 478 479 if (const auto it = _semantic_to_location.find(semantic); 480 it != _semantic_to_location.end()) 481 return it->second; 482 483 // Extract the semantic index from the semantic name (e.g. 2 for "TEXCOORD2") 484 size_t digit_index = semantic.size() - 1; 485 while (digit_index != 0 && semantic[digit_index] >= '0' && semantic[digit_index] <= '9') 486 digit_index--; 487 digit_index++; 488 489 const uint32_t semantic_digit = std::strtoul(semantic.c_str() + digit_index, nullptr, 10); 490 const std::string semantic_base = semantic.substr(0, digit_index); 491 492 uint32_t location = static_cast<uint32_t>(_semantic_to_location.size()); 493 494 // Now create adjoining location indices for all possible semantic indices belonging to this semantic name 495 for (uint32_t a = 0; a < semantic_digit + max_array_length; ++a) 496 { 497 const auto insert = _semantic_to_location.emplace(semantic_base + std::to_string(a), location + a); 498 if (!insert.second) 499 { 500 assert(a == 0 || (insert.first->second - a) == location); 501 502 // Semantic was already created with a different location index, so need to remap to that 503 location = insert.first->second - a; 504 } 505 } 506 507 return location + semantic_digit; 508 } 509 510 std::string escape_name(std::string name) const 511 { 512 static const std::unordered_set<std::string> s_reserverd_names = { 513 "common", "partition", "input", "output", "active", "filter", "superp", "invariant", 514 "attribute", "varying", "buffer", "resource", "coherent", "readonly", "writeonly", 515 "layout", "flat", "smooth", "lowp", "mediump", "highp", "precision", "patch", "subroutine", 516 "atomic_uint", "fixed", 517 "vec2", "vec3", "vec4", "ivec2", "dvec2", "dvec3", "dvec4", "ivec3", "ivec4", "uvec2", "uvec3", "uvec4", "bvec2", "bvec3", "bvec4", "fvec2", "fvec3", "fvec4", "hvec2", "hvec3", "hvec4", 518 "mat2", "mat3", "mat4", "dmat2", "dmat3", "dmat4", "mat2x2", "mat2x3", "mat2x4", "dmat2x2", "dmat2x3", "dmat2x4", "mat3x2", "mat3x3", "mat3x4", "dmat3x2", "dmat3x3", "dmat3x4", "mat4x2", "mat4x3", "mat4x4", "dmat4x2", "dmat4x3", "dmat4x4", 519 "sampler1DShadow", "sampler1DArrayShadow", "isampler1D", "isampler1DArray", "usampler1D", "usampler1DArray", 520 "sampler2DShadow", "sampler2DArrayShadow", "isampler2D", "isampler2DArray", "usampler2D", "usampler2DArray", "sampler2DRect", "sampler2DRectShadow", "isampler2DRect", "usampler2DRect", "isampler2DMS", "usampler2DMS", "isampler2DMSArray", "usampler2DMSArray", 521 "isampler3D", "usampler3D", "sampler3DRect", 522 "samplerCubeShadow", "samplerCubeArrayShadow", "isamplerCube", "isamplerCubeArray", "usamplerCube", "usamplerCubeArray", 523 "samplerBuffer", "isamplerBuffer", "usamplerBuffer", 524 "image1D", "iimage1D", "uimage1D", "image1DArray", "iimage1DArray", "uimage1DArray", 525 "image2D", "iimage2D", "uimage2D", "image2DArray", "iimage2DArray", "uimage2DArray", "image2DRect", "iimage2DRect", "uimage2DRect", "image2DMS", "iimage2DMS", "uimage2DMS", "image2DMSArray", "iimage2DMSArray", "uimage2DMSArray", 526 "image3D", "iimage3D", "uimage3D", 527 "imageCube", "iimageCube", "uimageCube", "imageCubeArray", "iimageCubeArray", "uimageCubeArray", 528 "imageBuffer", "iimageBuffer", "uimageBuffer", 529 "abs", "sign", "all", "any", "sin", "sinh", "cos", "cosh", "tan", "tanh", "asin", "acos", "atan", 530 "exp", "exp2", "log", "log2", "sqrt", "inversesqrt", "ceil", "floor", "fract", "trunc", "round", 531 "radians", "degrees", "length", "normalize", "transpose", "determinant", "intBitsToFloat", "uintBitsToFloat", 532 "floatBitsToInt", "floatBitsToUint", "matrixCompMult", "not", "lessThan", "greaterThan", "lessThanEqual", 533 "greaterThanEqual", "equal", "notEqual", "dot", "cross", "distance", "pow", "modf", "frexp", "ldexp", 534 "min", "max", "step", "reflect", "texture", "textureOffset", "fma", "mix", "clamp", "smoothstep", "refract", 535 "faceforward", "textureLod", "textureLodOffset", "texelFetch", "main" 536 }; 537 538 // Escape reserved names so that they do not fail to compile 539 if (name.compare(0, 3, "gl_") == 0 || s_reserverd_names.count(name)) 540 // Append an underscore at start instead of the end, since another one may get added in 'define_name' when there is a suffix 541 // This is guaranteed to not clash with user defined names, since those starting with an underscore are filtered out in 'define_name' 542 name = '_' + name; 543 544 // Remove duplicated underscore symbols from name which can occur due to namespaces but are not allowed in GLSL 545 for (size_t pos = 0; (pos = name.find("__", pos)) != std::string::npos;) 546 name.replace(pos, 2, "_"); 547 548 return name; 549 } 550 std::string semantic_to_builtin(std::string name, const std::string &semantic, shader_type stype) const 551 { 552 if (semantic == "SV_POSITION") 553 return stype == shader_type::ps ? "gl_FragCoord" : "gl_Position"; 554 if (semantic == "SV_POINTSIZE") 555 return "gl_PointSize"; 556 if (semantic == "SV_DEPTH") 557 return "gl_FragDepth"; 558 if (semantic == "SV_VERTEXID") 559 return _vulkan_semantics ? "gl_VertexIndex" : "gl_VertexID"; 560 if (semantic == "SV_ISFRONTFACE") 561 return "gl_FrontFacing"; 562 if (semantic == "SV_GROUPID") 563 return "gl_WorkGroupID"; 564 if (semantic == "SV_GROUPINDEX") 565 return "gl_LocalInvocationIndex"; 566 if (semantic == "SV_GROUPTHREADID") 567 return "gl_LocalInvocationID"; 568 if (semantic == "SV_DISPATCHTHREADID") 569 return "gl_GlobalInvocationID"; 570 571 return escape_name(std::move(name)); 572 } 573 574 static void increase_indentation_level(std::string &block) 575 { 576 if (block.empty()) 577 return; 578 579 for (size_t pos = 0; (pos = block.find("\n\t", pos)) != std::string::npos; pos += 3) 580 block.replace(pos, 2, "\n\t\t"); 581 582 block.insert(block.begin(), '\t'); 583 } 584 585 id define_struct(const location &loc, struct_info &info) override 586 { 587 info.definition = make_id(); 588 define_name<naming::unique>(info.definition, info.unique_name); 589 590 _structs.push_back(info); 591 592 std::string &code = _blocks.at(_current_block); 593 594 write_location(code, loc); 595 596 code += "struct " + id_to_name(info.definition) + "\n{\n"; 597 598 for (const struct_member_info &member : info.member_list) 599 { 600 code += '\t'; 601 write_type(code, member.type); // GLSL does not allow interpolation attributes on struct members 602 code += ' '; 603 code += escape_name(member.name); 604 if (member.type.is_array()) 605 code += '[' + std::to_string(member.type.array_length) + ']'; 606 code += ";\n"; 607 } 608 609 if (info.member_list.empty()) 610 code += "float _dummy;\n"; 611 612 code += "};\n"; 613 614 return info.definition; 615 } 616 id define_texture(const location &, texture_info &info) override 617 { 618 info.id = make_id(); 619 info.binding = ~0u; 620 621 _module.textures.push_back(info); 622 623 return info.id; 624 } 625 id define_sampler(const location &loc, const texture_info &, sampler_info &info) override 626 { 627 info.id = make_id(); 628 info.binding = _module.num_sampler_bindings++; 629 info.texture_binding = ~0u; // Unset texture bindings 630 631 define_name<naming::unique>(info.id, info.unique_name); 632 633 std::string &code = _blocks.at(_current_block); 634 635 write_location(code, loc); 636 637 code += "layout("; 638 if (_vulkan_semantics) 639 code += "set = 1, "; 640 #if 0 641 code += "binding = " + std::to_string(info.binding); 642 #else 643 code += "binding = /*SAMPLER:" + info.unique_name + "*/0"; 644 #endif 645 code += ") uniform "; 646 write_type(code, info.type); 647 code += ' ' + id_to_name(info.id) + ";\n"; 648 649 _module.samplers.push_back(info); 650 651 return info.id; 652 } 653 id define_storage(const location &loc, const texture_info &tex_info, storage_info &info) override 654 { 655 info.id = make_id(); 656 info.binding = _module.num_storage_bindings++; 657 658 define_name<naming::unique>(info.id, info.unique_name); 659 660 std::string &code = _blocks.at(_current_block); 661 662 write_location(code, loc); 663 664 code += "layout(binding = " + std::to_string(info.binding) + ", "; 665 write_texture_format(code, tex_info.format); 666 code += ") uniform "; 667 write_type(code, info.type); 668 code += ' ' + id_to_name(info.id) + ";\n"; 669 670 _module.storages.push_back(info); 671 672 return info.id; 673 } 674 id define_uniform(const location &loc, uniform_info &info) override 675 { 676 const id res = make_id(); 677 678 define_name<naming::unique>(res, info.name); 679 680 if (_uniforms_to_spec_constants && info.has_initializer_value) 681 { 682 info.size = info.type.components() * 4; 683 if (info.type.is_array()) 684 info.size *= info.type.array_length; 685 686 std::string &code = _blocks.at(_current_block); 687 688 write_location(code, loc); 689 690 assert(!info.type.has(type::q_static) && !info.type.has(type::q_const)); 691 692 code += "const "; 693 write_type(code, info.type); 694 code += ' ' + id_to_name(res) + " = "; 695 if (!info.type.is_scalar()) 696 write_type<false, false>(code, info.type); 697 code += "(SPEC_CONSTANT_" + info.name + ");\n"; 698 699 _module.spec_constants.push_back(info); 700 } 701 else 702 { 703 // GLSL specification on std140 layout: 704 // 1. If the member is a scalar consuming N basic machine units, the base alignment is N. 705 // 2. If the member is a two- or four-component vector with components consuming N basic machine units, the base alignment is 2N or 4N, respectively. 706 // 3. If the member is a three-component vector with components consuming N basic machine units, the base alignment is 4N. 707 // 4. If the member is an array of scalars or vectors, the base alignment and array stride are set to match the base alignment of a single array element, 708 // according to rules (1), (2), and (3), and rounded up to the base alignment of a four-component vector. 709 // 7. If the member is a row-major matrix with C columns and R rows, the matrix is stored identically to an array of R row vectors with C components each, according to rule (4). 710 // 8. If the member is an array of S row-major matrices with C columns and R rows, the matrix is stored identically to a row of S*R row vectors with C components each, according to rule (4). 711 uint32_t alignment = (info.type.rows == 3 ? 4 /* (3) */ : info.type.rows /* (2)*/) * 4 /* (1)*/; 712 info.size = info.type.rows * 4; 713 714 if (info.type.is_matrix()) 715 { 716 alignment = 16 /* (4) */; 717 info.size = info.type.rows * alignment /* (7), (8) */; 718 } 719 if (info.type.is_array()) 720 { 721 alignment = 16 /* (4) */; 722 info.size = align_up(info.size, alignment) * info.type.array_length; 723 } 724 725 // Adjust offset according to alignment rules from above 726 info.offset = _module.total_uniform_size; 727 info.offset = align_up(info.offset, alignment); 728 _module.total_uniform_size = info.offset + info.size; 729 730 write_location(_ubo_block, loc); 731 732 _ubo_block += '\t'; 733 // Note: All matrices are floating-point, even if the uniform type says different!! 734 write_type(_ubo_block, info.type); 735 _ubo_block += ' ' + id_to_name(res); 736 737 if (info.type.is_array()) 738 _ubo_block += '[' + std::to_string(info.type.array_length) + ']'; 739 740 _ubo_block += ";\n"; 741 742 _module.uniforms.push_back(info); 743 } 744 745 return res; 746 } 747 id define_variable(const location &loc, const type &type, std::string name, bool global, id initializer_value) override 748 { 749 const id res = make_id(); 750 751 // GLSL does not allow local sampler variables, so try to remap those 752 if (!global && type.is_sampler()) 753 return (_remapped_sampler_variables[res] = 0), res; 754 755 if (!name.empty()) 756 define_name<naming::general>(res, name); 757 758 std::string &code = _blocks.at(_current_block); 759 760 write_location(code, loc); 761 762 if (!global) 763 code += '\t'; 764 765 if (initializer_value != 0 && (type.has(type::q_const) && !_gles)) 766 code += "const "; 767 768 write_type(code, type); 769 code += ' ' + id_to_name(res); 770 771 if (type.is_array()) 772 code += '[' + std::to_string(type.array_length) + ']'; 773 774 if (initializer_value != 0) 775 code += " = " + id_to_name(initializer_value); 776 777 code += ";\n"; 778 779 return res; 780 } 781 id define_function(const location &loc, function_info &info) override 782 { 783 return define_function(loc, info, false); 784 } 785 786 id define_function(const location &loc, function_info &info, bool is_entry_point) 787 { 788 info.definition = make_id(); 789 790 // Name is used in other places like the "ENTRY_POINT" defines, so escape it here 791 info.unique_name = escape_name(info.unique_name); 792 793 if (!is_entry_point) 794 define_name<naming::unique>(info.definition, info.unique_name); 795 else 796 define_name<naming::reserved>(info.definition, "main"); 797 798 std::string &code = _blocks.at(_current_block); 799 800 write_location(code, loc); 801 802 write_type(code, info.return_type); 803 code += ' ' + id_to_name(info.definition) + '('; 804 805 assert(info.parameter_list.empty() || !is_entry_point); 806 807 for (size_t i = 0, num_params = info.parameter_list.size(); i < num_params; ++i) 808 { 809 auto ¶m = info.parameter_list[i]; 810 811 param.definition = make_id(); 812 define_name<naming::unique>(param.definition, param.name); 813 814 code += '\n'; 815 write_location(code, param.location); 816 code += '\t'; 817 write_type<true>(code, param.type); // GLSL does not allow interpolation attributes on function parameters 818 code += ' ' + id_to_name(param.definition); 819 820 if (param.type.is_array()) 821 code += '[' + std::to_string(param.type.array_length) + ']'; 822 823 if (i < num_params - 1) 824 code += ','; 825 } 826 827 code += ")\n"; 828 829 _functions.push_back(std::make_unique<function_info>(info)); 830 831 return info.definition; 832 } 833 834 void define_entry_point(function_info &func, shader_type stype, int num_threads[3]) override 835 { 836 // Modify entry point name so each thread configuration is made separate 837 if (stype == shader_type::cs) 838 func.unique_name = 'E' + func.unique_name + 839 '_' + std::to_string(num_threads[0]) + 840 '_' + std::to_string(num_threads[1]) + 841 '_' + std::to_string(num_threads[2]); 842 843 if (const auto it = std::find_if(_module.entry_points.begin(), _module.entry_points.end(), 844 [&func](const auto &ep) { return ep.name == func.unique_name; }); 845 it != _module.entry_points.end()) 846 return; 847 848 _module.entry_points.push_back({ func.unique_name, stype }); 849 850 _blocks.at(0) += "#ifdef ENTRY_POINT_" + func.unique_name + '\n'; 851 if (stype == shader_type::cs) 852 _blocks.at(0) += "layout(local_size_x = " + std::to_string(num_threads[0]) + 853 ", local_size_y = " + std::to_string(num_threads[1]) + 854 ", local_size_z = " + std::to_string(num_threads[2]) + ") in;\n"; 855 856 function_info entry_point; 857 entry_point.return_type = { type::t_void }; 858 859 std::unordered_map<std::string, std::string> semantic_to_varying_variable; 860 861 const auto create_varying_variable = [this, stype, &semantic_to_varying_variable](type type, unsigned int extra_qualifiers, const std::string &name, const std::string &semantic) { 862 // Skip built in variables 863 if (!semantic_to_builtin(std::string(), semantic, stype).empty()) 864 return; 865 866 // Do not create multiple input/output variables for duplicate semantic usage (since every input/output location may only be defined once in GLSL) 867 if ((extra_qualifiers & type::q_in) != 0 && 868 !semantic_to_varying_variable.emplace(semantic, name).second) 869 return; 870 871 type.qualifiers |= extra_qualifiers; 872 assert((type.has(type::q_in) || type.has(type::q_out)) && !type.has(type::q_inout)); 873 874 // OpenGL does not allow varying of type boolean 875 if (type.is_boolean()) 876 type.base = type::t_float; 877 878 std::string &code = _blocks.at(_current_block); 879 880 const int array_length = std::max(1, type.array_length); 881 const uint32_t location = semantic_to_location(semantic, array_length); 882 883 for (int a = 0; a < array_length; ++a) 884 { 885 code += "layout(location = " + std::to_string(location + a) + ") "; 886 write_type<false, false, true>(code, type); 887 code += ' '; 888 code += escape_name(type.is_array() ? 889 name + '_' + std::to_string(a) : 890 name); 891 code += ";\n"; 892 } 893 }; 894 895 // Translate function parameters to input/output variables 896 if (func.return_type.is_struct()) 897 { 898 const struct_info &definition = get_struct(func.return_type.definition); 899 900 for (const struct_member_info &member : definition.member_list) 901 create_varying_variable(member.type, type::q_out, "_return_" + member.name, member.semantic); 902 } 903 else if (!func.return_type.is_void()) 904 { 905 create_varying_variable(func.return_type, type::q_out, "_return", func.return_semantic); 906 } 907 908 const auto num_params = func.parameter_list.size(); 909 for (size_t i = 0; i < num_params; ++i) 910 { 911 type param_type = func.parameter_list[i].type; 912 param_type.qualifiers &= ~type::q_inout; 913 914 // Create separate input/output variables for "inout" parameters (since "inout" is not valid on those in GLSL) 915 if (func.parameter_list[i].type.has(type::q_in)) 916 { 917 // Flatten structure parameters 918 if (param_type.is_struct()) 919 { 920 const struct_info &definition = get_struct(param_type.definition); 921 922 for (int a = 0, array_length = std::max(1, param_type.array_length); a < array_length; a++) 923 for (const struct_member_info &member : definition.member_list) 924 create_varying_variable(member.type, param_type.qualifiers | type::q_in, "_in_param" + std::to_string(i) + '_' + std::to_string(a) + '_' + member.name, member.semantic); 925 } 926 else 927 { 928 create_varying_variable(param_type, type::q_in, "_in_param" + std::to_string(i), func.parameter_list[i].semantic); 929 } 930 } 931 932 if (func.parameter_list[i].type.has(type::q_out)) 933 { 934 if (param_type.is_struct()) 935 { 936 const struct_info &definition = get_struct(param_type.definition); 937 938 for (int a = 0, array_length = std::max(1, param_type.array_length); a < array_length; a++) 939 for (const struct_member_info &member : definition.member_list) 940 create_varying_variable(member.type, param_type.qualifiers | type::q_out, "_out_param" + std::to_string(i) + '_' + std::to_string(a) + '_' + member.name, member.semantic); 941 } 942 else 943 { 944 create_varying_variable(param_type, type::q_out, "_out_param" + std::to_string(i), func.parameter_list[i].semantic); 945 } 946 } 947 } 948 949 // Translate return value to output variable 950 define_function({}, entry_point, true); 951 enter_block(create_block()); 952 953 std::string &code = _blocks.at(_current_block); 954 955 // Handle input parameters 956 for (size_t i = 0; i < num_params; ++i) 957 { 958 const type ¶m_type = func.parameter_list[i].type; 959 960 if (param_type.has(type::q_in)) 961 { 962 // Create local array element variables 963 for (int a = 0, array_length = std::max(1, param_type.array_length); a < array_length; a++) 964 { 965 if (param_type.is_struct()) 966 { 967 // Build struct from separate member input variables 968 code += '\t'; 969 write_type<false, true>(code, param_type); 970 code += ' '; 971 code += escape_name(param_type.is_array() ? 972 "_in_param" + std::to_string(i) + '_' + std::to_string(a) : 973 "_in_param" + std::to_string(i)); 974 code += " = "; 975 write_type<false, false>(code, param_type); 976 code += '('; 977 978 const struct_info &definition = get_struct(param_type.definition); 979 980 for (const struct_member_info &member : definition.member_list) 981 { 982 std::string in_param_name = "_in_param" + std::to_string(i) + '_' + std::to_string(a) + '_' + member.name; 983 if (const auto it = semantic_to_varying_variable.find(member.semantic); 984 it != semantic_to_varying_variable.end() && it->second != in_param_name) 985 in_param_name = it->second; 986 987 if (member.type.is_array()) 988 { 989 write_type<false, false>(code, member.type); 990 code += "[]("; 991 992 for (int b = 0; b < member.type.array_length; b++) 993 { 994 // OpenGL does not allow varying of type boolean, so need to cast here 995 if (member.type.is_boolean()) 996 { 997 write_type<false, false>(code, member.type); 998 code += '('; 999 } 1000 1001 code += escape_name(in_param_name + '_' + std::to_string(b)); 1002 1003 if (member.type.is_boolean()) 1004 code += ')'; 1005 1006 if (b < member.type.array_length - 1) 1007 code += ", "; 1008 } 1009 1010 code += ')'; 1011 } 1012 else 1013 { 1014 if (member.type.is_boolean() || (_gles && member.type.is_integral())) 1015 { 1016 write_type<false, false>(code, member.type); 1017 code += '('; 1018 } 1019 1020 code += semantic_to_builtin(std::move(in_param_name), member.semantic, stype); 1021 1022 if (member.type.is_boolean() || (_gles && member.type.is_integral())) 1023 code += ')'; 1024 } 1025 1026 code += ", "; 1027 } 1028 1029 // There can be no empty structs, so can assume that the last two characters are always ", " 1030 code.pop_back(); 1031 code.pop_back(); 1032 1033 code += ");\n"; 1034 } 1035 else if (const auto it = semantic_to_varying_variable.find(func.parameter_list[i].semantic); 1036 it != semantic_to_varying_variable.end() && it->second != "_in_param" + std::to_string(i)) 1037 { 1038 // Create local variables for duplicated semantics (since no input/output variable is created for those, see 'create_varying_variable') 1039 code += '\t'; 1040 write_type<false, true>(code, param_type); 1041 code += ' '; 1042 code += escape_name(param_type.is_array() ? 1043 "_in_param" + std::to_string(i) + '_' + std::to_string(a) : 1044 "_in_param" + std::to_string(i)); 1045 code += " = "; 1046 1047 if (param_type.is_boolean()) 1048 { 1049 write_type<false, false>(code, param_type); 1050 code += '('; 1051 } 1052 1053 code += escape_name(param_type.is_array() ? 1054 it->second + '_' + std::to_string(a) : 1055 it->second); 1056 1057 if (param_type.is_boolean()) 1058 code += ')'; 1059 1060 code += ";\n"; 1061 } 1062 } 1063 } 1064 1065 // Create local parameter variables which are used as arguments in the entry point function call below 1066 code += '\t'; 1067 write_type<false, true>(code, param_type); 1068 code += ' '; 1069 code += escape_name("_param" + std::to_string(i)); 1070 if (param_type.is_array()) 1071 code += '[' + std::to_string(param_type.array_length) + ']'; 1072 1073 // Initialize those local variables with the input value if existing 1074 // Parameters with only an "out" qualifier are written to by the entry point function, so do not need to be initialized 1075 if (param_type.has(type::q_in)) 1076 { 1077 code += " = "; 1078 1079 // Build array from separate array element variables 1080 if (param_type.is_array()) 1081 { 1082 write_type<false, false>(code, param_type); 1083 code += "[]("; 1084 1085 for (int a = 0; a < param_type.array_length; ++a) 1086 { 1087 // OpenGL does not allow varying of type boolean, so need to cast here 1088 if (param_type.is_boolean()) 1089 { 1090 write_type<false, false>(code, param_type); 1091 code += '('; 1092 } 1093 1094 code += escape_name("_in_param" + std::to_string(i) + '_' + std::to_string(a)); 1095 1096 if (param_type.is_boolean()) 1097 code += ')'; 1098 1099 if (a < param_type.array_length - 1) 1100 code += ", "; 1101 } 1102 1103 code += ')'; 1104 } 1105 else 1106 { 1107 if (param_type.is_boolean() || (_gles && param_type.is_integral())) 1108 { 1109 write_type<false, false>(code, param_type); 1110 code += '('; 1111 } 1112 1113 code += semantic_to_builtin("_in_param" + std::to_string(i), func.parameter_list[i].semantic, stype); 1114 1115 if (param_type.is_boolean() || (_gles && param_type.is_integral())) 1116 code += ')'; 1117 } 1118 } 1119 1120 code += ";\n"; 1121 } 1122 1123 code += '\t'; 1124 // Structs cannot be output variables, so have to write to a temporary first and then output each member separately 1125 if (func.return_type.is_struct()) 1126 { 1127 write_type(code, func.return_type); 1128 code += " _return = "; 1129 } 1130 // All other output types can write to the output variable directly 1131 else if (!func.return_type.is_void()) 1132 { 1133 code += semantic_to_builtin("_return", func.return_semantic, stype); 1134 code += " = "; 1135 } 1136 1137 // Call the function this entry point refers to 1138 code += id_to_name(func.definition) + '('; 1139 1140 for (size_t i = 0; i < num_params; ++i) 1141 { 1142 code += "_param" + std::to_string(i); 1143 1144 if (i < num_params - 1) 1145 code += ", "; 1146 } 1147 1148 code += ");\n"; 1149 1150 // Handle output parameters 1151 for (size_t i = 0; i < num_params; ++i) 1152 { 1153 const type ¶m_type = func.parameter_list[i].type; 1154 if (!param_type.has(type::q_out)) 1155 continue; 1156 1157 if (param_type.is_struct()) 1158 { 1159 const struct_info &definition = get_struct(param_type.definition); 1160 1161 // Split out struct fields into separate output variables again 1162 for (int a = 0, array_length = std::max(1, param_type.array_length); a < array_length; a++) 1163 { 1164 for (const struct_member_info &member : definition.member_list) 1165 { 1166 if (member.type.is_array()) 1167 { 1168 for (int b = 0; b < member.type.array_length; b++) 1169 { 1170 code += '\t'; 1171 code += escape_name("_out_param" + std::to_string(i) + '_' + std::to_string(a) + '_' + member.name + '_' + std::to_string(b)); 1172 code += " = "; 1173 1174 // OpenGL does not allow varying of type boolean, so need to cast here 1175 if (member.type.is_boolean()) 1176 { 1177 type varying_type = member.type; 1178 varying_type.base = type::t_float; 1179 write_type<false, false>(code, varying_type); 1180 code += '('; 1181 } 1182 1183 code += escape_name("_param" + std::to_string(i)); 1184 if (param_type.is_array()) 1185 code += '[' + std::to_string(a) + ']'; 1186 code += '.'; 1187 code += member.name; 1188 code += '[' + std::to_string(b) + ']'; 1189 1190 if (member.type.is_boolean()) 1191 code += ')'; 1192 1193 code += ";\n"; 1194 } 1195 } 1196 else 1197 { 1198 code += '\t'; 1199 code += semantic_to_builtin("_out_param" + std::to_string(i) + '_' + std::to_string(a) + '_' + member.name, member.semantic, stype); 1200 code += " = "; 1201 1202 if (member.type.is_boolean()) 1203 { 1204 type varying_type = member.type; 1205 varying_type.base = type::t_float; 1206 write_type<false, false>(code, varying_type); 1207 code += '('; 1208 } 1209 1210 code += escape_name("_param" + std::to_string(i)); 1211 if (param_type.is_array()) 1212 code += '[' + std::to_string(a) + ']'; 1213 code += '.'; 1214 code += member.name; 1215 1216 if (member.type.is_boolean()) 1217 code += ')'; 1218 1219 code += ";\n"; 1220 } 1221 } 1222 } 1223 } 1224 else 1225 { 1226 if (param_type.is_array()) 1227 { 1228 // Split up array output into individual array elements again 1229 for (int a = 0; a < param_type.array_length; a++) 1230 { 1231 code += '\t'; 1232 code += escape_name("_out_param" + std::to_string(i) + '_' + std::to_string(a)); 1233 code += " = "; 1234 1235 // OpenGL does not allow varying of type boolean, so need to cast here 1236 if (param_type.is_boolean()) 1237 { 1238 type varying_type = param_type; 1239 varying_type.base = type::t_float; 1240 write_type<false, false>(code, varying_type); 1241 code += '('; 1242 } 1243 1244 code += escape_name("_param" + std::to_string(i)); 1245 code += '[' + std::to_string(a) + ']'; 1246 1247 if (param_type.is_boolean()) 1248 code += ')'; 1249 1250 code += ";\n"; 1251 } 1252 } 1253 else 1254 { 1255 code += '\t'; 1256 code += semantic_to_builtin("_out_param" + std::to_string(i), func.parameter_list[i].semantic, stype); 1257 code += " = "; 1258 1259 if (param_type.is_boolean()) 1260 { 1261 type varying_type = param_type; 1262 varying_type.base = type::t_float; 1263 write_type<false, false>(code, varying_type); 1264 code += '('; 1265 } 1266 1267 code += escape_name("_param" + std::to_string(i)); 1268 1269 if (param_type.is_boolean()) 1270 code += ')'; 1271 1272 code += ";\n"; 1273 } 1274 } 1275 } 1276 1277 // Handle return struct output variables 1278 if (func.return_type.is_struct()) 1279 { 1280 const struct_info &definition = get_struct(func.return_type.definition); 1281 1282 for (const struct_member_info &member : definition.member_list) 1283 { 1284 code += '\t'; 1285 code += semantic_to_builtin("_return_" + member.name, member.semantic, stype); 1286 code += " = _return." + escape_name(member.name) + ";\n"; 1287 } 1288 } 1289 1290 // Add code to flip the output vertically 1291 if (_flip_vert_y && stype == shader_type::vs) 1292 code += "\tgl_Position.y = -gl_Position.y;\n"; 1293 1294 leave_block_and_return(0); 1295 leave_function(); 1296 1297 _blocks.at(0) += "#endif\n"; 1298 } 1299 1300 id emit_load(const expression &exp, bool force_new_id) override 1301 { 1302 if (exp.is_constant) 1303 return emit_constant(exp.type, exp.constant); 1304 else if (exp.chain.empty() && !force_new_id) // Can refer to values without access chain directly 1305 return exp.base; 1306 1307 const id res = make_id(); 1308 1309 std::string type, expr_code = id_to_name(exp.base); 1310 1311 for (const auto &op : exp.chain) 1312 { 1313 switch (op.op) 1314 { 1315 case expression::operation::op_cast: 1316 type.clear(); 1317 write_type<false, false>(type, op.to); 1318 expr_code = type + '(' + expr_code + ')'; 1319 break; 1320 case expression::operation::op_member: 1321 expr_code += '.'; 1322 expr_code += escape_name(get_struct(op.from.definition).member_list[op.index].name); 1323 break; 1324 case expression::operation::op_dynamic_index: 1325 // For matrices this will extract a column, but that is fine, since they are initialized column-wise too 1326 // Also cast to an integer, since it could be a boolean too, but GLSL does not allow those in index expressions 1327 expr_code += "[int(" + id_to_name(op.index) + ")]"; 1328 break; 1329 case expression::operation::op_constant_index: 1330 if (op.from.is_vector() && !op.from.is_array()) 1331 expr_code += '.', 1332 expr_code += "xyzw"[op.index]; 1333 else 1334 expr_code += '[' + std::to_string(op.index) + ']'; 1335 break; 1336 case expression::operation::op_swizzle: 1337 if (op.from.is_matrix()) 1338 { 1339 if (op.swizzle[1] < 0) 1340 { 1341 const int row = (op.swizzle[0] % 4); 1342 const int col = (op.swizzle[0] - row) / 4; 1343 1344 expr_code += '[' + std::to_string(row) + "][" + std::to_string(col) + ']'; 1345 } 1346 else 1347 { 1348 // TODO: Implement matrix to vector swizzles 1349 assert(false); 1350 expr_code += "_NOT_IMPLEMENTED_"; // Make sure compilation fails 1351 } 1352 } 1353 else 1354 { 1355 // can't swizzle scalars 1356 if (_gles && op.from.is_scalar()) 1357 { 1358 // => e.g. vec3(expr, expr, expr).xyz 1359 type.clear(); 1360 write_type<false, false>(type, op.to); 1361 std::string new_code = type; 1362 new_code += '('; 1363 1364 const unsigned int components = op.to.components(); 1365 for (unsigned int i = 0; i < components; ++i) 1366 { 1367 if (i > 0) 1368 new_code += ','; 1369 new_code += '(' + expr_code + ')'; 1370 } 1371 new_code += ')'; 1372 expr_code = std::move(new_code); 1373 } 1374 else 1375 { 1376 expr_code += '.'; 1377 for (unsigned int i = 0; i < 4 && op.swizzle[i] >= 0; ++i) 1378 expr_code += "xyzw"[op.swizzle[i]]; 1379 } 1380 } 1381 break; 1382 } 1383 } 1384 1385 // GLSL matrices are always floating point, so need to cast result to the target type 1386 if (!exp.chain.empty() && exp.chain[0].from.is_matrix() && !exp.chain[0].from.is_floating_point()) 1387 { 1388 type.clear(); 1389 write_type<false, false>(type, exp.type); 1390 expr_code = type + '(' + expr_code + ')'; 1391 } 1392 1393 if (force_new_id) 1394 { 1395 // Need to store value in a new variable to comply with request for a new ID 1396 std::string &code = _blocks.at(_current_block); 1397 1398 code += '\t'; 1399 write_type(code, exp.type); 1400 code += ' ' + id_to_name(res) + " = " + expr_code + ";\n"; 1401 } 1402 else 1403 { 1404 // Avoid excessive variable definitions by instancing simple load operations in code every time 1405 define_name<naming::expression>(res, std::move(expr_code)); 1406 } 1407 1408 return res; 1409 } 1410 void emit_store(const expression &exp, id value) override 1411 { 1412 if (const auto it = _remapped_sampler_variables.find(exp.base); 1413 it != _remapped_sampler_variables.end()) 1414 { 1415 assert(it->second == 0); 1416 it->second = value; 1417 return; 1418 } 1419 1420 std::string &code = _blocks.at(_current_block); 1421 1422 write_location(code, exp.location); 1423 1424 code += '\t' + id_to_name(exp.base); 1425 1426 for (const auto &op : exp.chain) 1427 { 1428 switch (op.op) 1429 { 1430 case expression::operation::op_member: 1431 code += '.'; 1432 code += escape_name(get_struct(op.from.definition).member_list[op.index].name); 1433 break; 1434 case expression::operation::op_dynamic_index: 1435 code += "[int(" + id_to_name(op.index) + ")]"; 1436 break; 1437 case expression::operation::op_constant_index: 1438 code += '[' + std::to_string(op.index) + ']'; 1439 break; 1440 case expression::operation::op_swizzle: 1441 if (op.from.is_matrix()) 1442 { 1443 if (op.swizzle[1] < 0) 1444 { 1445 const int row = (op.swizzle[0] % 4); 1446 const int col = (op.swizzle[0] - row) / 4; 1447 1448 code += '[' + std::to_string(row) + "][" + std::to_string(col) + ']'; 1449 } 1450 else 1451 { 1452 // TODO: Implement matrix to vector swizzles 1453 assert(false); 1454 code += "_NOT_IMPLEMENTED_"; // Make sure compilation fails 1455 } 1456 } 1457 else 1458 { 1459 code += '.'; 1460 for (unsigned int i = 0; i < 4 && op.swizzle[i] >= 0; ++i) 1461 code += "xyzw"[op.swizzle[i]]; 1462 } 1463 break; 1464 } 1465 } 1466 1467 code += " = "; 1468 1469 // GLSL matrices are always floating point, so need to cast type 1470 if (!exp.chain.empty() && exp.chain[0].from.is_matrix() && !exp.chain[0].from.is_floating_point()) 1471 // Only supporting scalar assignments to matrices currently, so can assume to always cast to float 1472 code += "float(" + id_to_name(value) + ");\n"; 1473 else 1474 code += id_to_name(value) + ";\n"; 1475 } 1476 1477 id emit_constant(const type &type, const constant &data) override 1478 { 1479 const id res = make_id(); 1480 1481 if (type.is_array() || type.is_struct()) 1482 { 1483 assert(type.has(type::q_const)); 1484 1485 std::string &code = _blocks.at(_current_block); 1486 1487 code += '\t'; 1488 1489 // GLSL requires constants to be initialized, but struct initialization is not supported right now 1490 if (!type.is_struct()) 1491 code += "const "; 1492 1493 write_type(code, type); 1494 code += ' ' + id_to_name(res); 1495 1496 // Array constants need to be stored in a constant variable as they cannot be used in-place 1497 if (type.is_array()) 1498 code += '[' + std::to_string(type.array_length) + ']'; 1499 1500 // Struct initialization is not supported right now 1501 if (!type.is_struct()) { 1502 code += " = "; 1503 write_constant(code, type, data); 1504 } 1505 1506 code += ";\n"; 1507 return res; 1508 } 1509 1510 std::string code; 1511 write_constant(code, type, data); 1512 define_name<naming::expression>(res, std::move(code)); 1513 1514 return res; 1515 } 1516 1517 id emit_unary_op(const location &loc, tokenid op, const type &res_type, id val) override 1518 { 1519 const id res = make_id(); 1520 1521 std::string &code = _blocks.at(_current_block); 1522 1523 write_location(code, loc); 1524 1525 code += '\t'; 1526 write_type(code, res_type); 1527 code += ' ' + id_to_name(res) + " = "; 1528 1529 switch (op) 1530 { 1531 case tokenid::minus: 1532 code += '-'; 1533 break; 1534 case tokenid::tilde: 1535 code += '~'; 1536 break; 1537 case tokenid::exclaim: 1538 if (res_type.is_vector()) 1539 code += "not"; 1540 else 1541 code += "!bool"; 1542 break; 1543 default: 1544 assert(false); 1545 } 1546 1547 code += '(' + id_to_name(val) + ");\n"; 1548 1549 return res; 1550 } 1551 id emit_binary_op(const location &loc, tokenid op, const type &res_type, const type &type, id lhs, id rhs) override 1552 { 1553 const id res = make_id(); 1554 1555 std::string &code = _blocks.at(_current_block); 1556 1557 write_location(code, loc); 1558 1559 code += '\t'; 1560 write_type(code, res_type); 1561 code += ' ' + id_to_name(res) + " = "; 1562 1563 std::string intrinsic, operator_code; 1564 1565 switch (op) 1566 { 1567 case tokenid::plus: 1568 case tokenid::plus_plus: 1569 case tokenid::plus_equal: 1570 operator_code = '+'; 1571 break; 1572 case tokenid::minus: 1573 case tokenid::minus_minus: 1574 case tokenid::minus_equal: 1575 operator_code = '-'; 1576 break; 1577 case tokenid::star: 1578 case tokenid::star_equal: 1579 if (type.is_matrix()) 1580 intrinsic = "matrixCompMult"; 1581 else 1582 operator_code = '*'; 1583 break; 1584 case tokenid::slash: 1585 case tokenid::slash_equal: 1586 operator_code = '/'; 1587 break; 1588 case tokenid::percent: 1589 case tokenid::percent_equal: 1590 if (type.is_floating_point()) 1591 intrinsic = "fmodHLSL", 1592 _uses_fmod = true; 1593 else 1594 operator_code = '%'; 1595 break; 1596 case tokenid::caret: 1597 case tokenid::caret_equal: 1598 operator_code = '^'; 1599 break; 1600 case tokenid::pipe: 1601 case tokenid::pipe_equal: 1602 operator_code = '|'; 1603 break; 1604 case tokenid::ampersand: 1605 case tokenid::ampersand_equal: 1606 operator_code = '&'; 1607 break; 1608 case tokenid::less_less: 1609 case tokenid::less_less_equal: 1610 operator_code = "<<"; 1611 break; 1612 case tokenid::greater_greater: 1613 case tokenid::greater_greater_equal: 1614 operator_code = ">>"; 1615 break; 1616 case tokenid::pipe_pipe: 1617 if (type.is_vector()) 1618 intrinsic = "compOr", 1619 _uses_componentwise_or = true; 1620 else 1621 operator_code = "||"; 1622 break; 1623 case tokenid::ampersand_ampersand: 1624 if (type.is_vector()) 1625 intrinsic = "compAnd", 1626 _uses_componentwise_and = true; 1627 else 1628 operator_code = "&&"; 1629 break; 1630 case tokenid::less: 1631 if (type.is_vector()) 1632 intrinsic = "lessThan"; 1633 else 1634 operator_code = '<'; 1635 break; 1636 case tokenid::less_equal: 1637 if (type.is_vector()) 1638 intrinsic = "lessThanEqual"; 1639 else 1640 operator_code = "<="; 1641 break; 1642 case tokenid::greater: 1643 if (type.is_vector()) 1644 intrinsic = "greaterThan"; 1645 else 1646 operator_code = '>'; 1647 break; 1648 case tokenid::greater_equal: 1649 if (type.is_vector()) 1650 intrinsic = "greaterThanEqual"; 1651 else 1652 operator_code = ">="; 1653 break; 1654 case tokenid::equal_equal: 1655 if (type.is_vector()) 1656 intrinsic = "equal"; 1657 else 1658 operator_code = "=="; 1659 break; 1660 case tokenid::exclaim_equal: 1661 if (type.is_vector()) 1662 intrinsic = "notEqual"; 1663 else 1664 operator_code = "!="; 1665 break; 1666 default: 1667 assert(false); 1668 } 1669 1670 if (!intrinsic.empty()) 1671 code += intrinsic + '(' + id_to_name(lhs) + ", " + id_to_name(rhs) + ')'; 1672 else 1673 code += id_to_name(lhs) + ' ' + operator_code + ' ' + id_to_name(rhs); 1674 1675 code += ";\n"; 1676 1677 return res; 1678 } 1679 id emit_ternary_op(const location &loc, tokenid op, const type &res_type, id condition, id true_value, id false_value) override 1680 { 1681 if (op != tokenid::question) 1682 return assert(false), 0; // Should never happen, since this is the only ternary operator currently supported 1683 1684 const id res = make_id(); 1685 1686 std::string &code = _blocks.at(_current_block); 1687 1688 write_location(code, loc); 1689 1690 code += '\t'; 1691 write_type(code, res_type); 1692 code += ' ' + id_to_name(res); 1693 1694 if (res_type.is_array()) 1695 code += '[' + std::to_string(res_type.array_length) + ']'; 1696 1697 code += " = "; 1698 1699 if (res_type.is_vector()) 1700 code += "compCond(" + id_to_name(condition) + ", " + id_to_name(true_value) + ", " + id_to_name(false_value) + ");\n", 1701 _uses_componentwise_cond = true; 1702 else // GLSL requires the conditional expression to be a scalar boolean 1703 code += id_to_name(condition) + " ? " + id_to_name(true_value) + " : " + id_to_name(false_value) + ";\n"; 1704 1705 return res; 1706 } 1707 id emit_call(const location &loc, id function, const type &res_type, const std::vector<expression> &args) override 1708 { 1709 #ifndef NDEBUG 1710 for (const expression &arg : args) 1711 assert(arg.chain.empty() && arg.base != 0); 1712 #endif 1713 1714 const id res = make_id(); 1715 1716 std::string &code = _blocks.at(_current_block); 1717 1718 write_location(code, loc); 1719 1720 code += '\t'; 1721 1722 if (!res_type.is_void()) 1723 { 1724 write_type(code, res_type); 1725 code += ' ' + id_to_name(res); 1726 1727 if (res_type.is_array()) 1728 code += '[' + std::to_string(res_type.array_length) + ']'; 1729 1730 code += " = "; 1731 } 1732 1733 code += id_to_name(function) + '('; 1734 1735 for (size_t i = 0, num_args = args.size(); i < num_args; ++i) 1736 { 1737 code += id_to_name(args[i].base); 1738 1739 if (i < num_args - 1) 1740 code += ", "; 1741 } 1742 1743 code += ");\n"; 1744 1745 return res; 1746 } 1747 id emit_call_intrinsic(const location &loc, id intrinsic, const type &res_type, const std::vector<expression> &args) override 1748 { 1749 #ifndef NDEBUG 1750 for (const expression &arg : args) 1751 assert(arg.chain.empty() && arg.base != 0); 1752 #endif 1753 1754 const id res = make_id(); 1755 1756 std::string &code = _blocks.at(_current_block); 1757 1758 write_location(code, loc); 1759 1760 code += '\t'; 1761 1762 if (!res_type.is_void()) 1763 { 1764 write_type(code, res_type); 1765 code += ' ' + id_to_name(res) + " = "; 1766 } 1767 1768 enum 1769 { 1770 #define IMPLEMENT_INTRINSIC_GLSL(name, i, code) name##i, 1771 #include "effect_symbol_table_intrinsics.inl" 1772 }; 1773 1774 switch (intrinsic) 1775 { 1776 #define IMPLEMENT_INTRINSIC_GLSL(name, i, code) case name##i: code break; 1777 #include "effect_symbol_table_intrinsics.inl" 1778 default: 1779 assert(false); 1780 } 1781 1782 code += ";\n"; 1783 1784 return res; 1785 } 1786 id emit_construct(const location &loc, const type &type, const std::vector<expression> &args) override 1787 { 1788 #ifndef NDEBUG 1789 for (const auto &arg : args) 1790 assert((arg.type.is_scalar() || type.is_array()) && arg.chain.empty() && arg.base != 0); 1791 #endif 1792 1793 const id res = make_id(); 1794 1795 std::string &code = _blocks.at(_current_block); 1796 1797 write_location(code, loc); 1798 1799 code += '\t'; 1800 write_type(code, type); 1801 code += ' ' + id_to_name(res); 1802 1803 if (type.is_array()) 1804 code += '[' + std::to_string(type.array_length) + ']'; 1805 1806 code += " = "; 1807 1808 write_type<false, false>(code, type); 1809 1810 if (type.is_array()) 1811 code += '[' + std::to_string(type.array_length) + ']'; 1812 1813 code += '('; 1814 1815 for (size_t i = 0, num_args = args.size(); i < num_args; ++i) 1816 { 1817 code += id_to_name(args[i].base); 1818 1819 if (i < num_args - 1) 1820 code += ", "; 1821 } 1822 1823 code += ");\n"; 1824 1825 return res; 1826 } 1827 1828 void emit_if(const location &loc, id condition_value, id condition_block, id true_statement_block, id false_statement_block, unsigned int flags) override 1829 { 1830 assert(condition_value != 0 && condition_block != 0 && true_statement_block != 0 && false_statement_block != 0); 1831 1832 std::string &code = _blocks.at(_current_block); 1833 1834 std::string &true_statement_data = _blocks.at(true_statement_block); 1835 std::string &false_statement_data = _blocks.at(false_statement_block); 1836 1837 increase_indentation_level(true_statement_data); 1838 increase_indentation_level(false_statement_data); 1839 1840 code += _blocks.at(condition_block); 1841 1842 write_location(code, loc); 1843 1844 if (flags != 0 && !_gles) 1845 { 1846 _enable_control_flow_attributes = true; 1847 1848 code += "#if GL_EXT_control_flow_attributes\n\t[["; 1849 if ((flags & 0x1) == 0x1) 1850 code += "flatten"; 1851 if ((flags & 0x3) == 0x3) 1852 code += ", "; 1853 if ((flags & 0x2) == 0x2) 1854 code += "dont_flatten"; 1855 code += "]]\n#endif\n"; 1856 } 1857 1858 code += '\t'; 1859 code += "if (" + id_to_name(condition_value) + ")\n\t{\n"; 1860 code += true_statement_data; 1861 code += "\t}\n"; 1862 1863 if (!false_statement_data.empty()) 1864 { 1865 code += "\telse\n\t{\n"; 1866 code += false_statement_data; 1867 code += "\t}\n"; 1868 } 1869 1870 // Remove consumed blocks to save memory 1871 _blocks.erase(condition_block); 1872 _blocks.erase(true_statement_block); 1873 _blocks.erase(false_statement_block); 1874 } 1875 id emit_phi(const location &loc, id condition_value, id condition_block, id true_value, id true_statement_block, id false_value, id false_statement_block, const type &type) override 1876 { 1877 assert(condition_value != 0 && condition_block != 0 && true_value != 0 && true_statement_block != 0 && false_value != 0 && false_statement_block != 0); 1878 1879 std::string &code = _blocks.at(_current_block); 1880 1881 std::string &true_statement_data = _blocks.at(true_statement_block); 1882 std::string &false_statement_data = _blocks.at(false_statement_block); 1883 1884 increase_indentation_level(true_statement_data); 1885 increase_indentation_level(false_statement_data); 1886 1887 const id res = make_id(); 1888 1889 code += _blocks.at(condition_block); 1890 1891 code += '\t'; 1892 write_type(code, type); 1893 code += ' ' + id_to_name(res) + ";\n"; 1894 1895 write_location(code, loc); 1896 1897 code += "\tif (" + id_to_name(condition_value) + ")\n\t{\n"; 1898 code += (true_statement_block != condition_block ? true_statement_data : std::string()); 1899 code += "\t\t" + id_to_name(res) + " = " + id_to_name(true_value) + ";\n"; 1900 code += "\t}\n\telse\n\t{\n"; 1901 code += (false_statement_block != condition_block ? false_statement_data : std::string()); 1902 code += "\t\t" + id_to_name(res) + " = " + id_to_name(false_value) + ";\n"; 1903 code += "\t}\n"; 1904 1905 // Remove consumed blocks to save memory 1906 _blocks.erase(condition_block); 1907 _blocks.erase(true_statement_block); 1908 _blocks.erase(false_statement_block); 1909 1910 return res; 1911 } 1912 void emit_loop(const location &loc, id condition_value, id prev_block, id header_block, id condition_block, id loop_block, id continue_block, unsigned int flags) override 1913 { 1914 assert(prev_block != 0 && header_block != 0 && loop_block != 0 && continue_block != 0); 1915 1916 std::string &code = _blocks.at(_current_block); 1917 1918 std::string &loop_data = _blocks.at(loop_block); 1919 std::string &continue_data = _blocks.at(continue_block); 1920 1921 increase_indentation_level(loop_data); 1922 increase_indentation_level(loop_data); 1923 increase_indentation_level(continue_data); 1924 1925 code += _blocks.at(prev_block); 1926 1927 std::string attributes; 1928 if (flags != 0 && !_gles) 1929 { 1930 _enable_control_flow_attributes = true; 1931 1932 attributes += "#if GL_EXT_control_flow_attributes\n\t[["; 1933 if ((flags & 0x1) == 0x1) 1934 attributes += "unroll"; 1935 if ((flags & 0x3) == 0x3) 1936 attributes += ", "; 1937 if ((flags & 0x2) == 0x2) 1938 attributes += "dont_unroll"; 1939 attributes += "]]\n#endif\n"; 1940 } 1941 1942 // Condition value can be missing in infinite loop constructs like "for (;;)" 1943 std::string condition_name = condition_value != 0 ? id_to_name(condition_value) : "true"; 1944 1945 if (condition_block == 0) 1946 { 1947 // Convert the last SSA variable initializer to an assignment statement 1948 auto pos_assign = continue_data.rfind(condition_name); 1949 auto pos_prev_assign = continue_data.rfind('\t', pos_assign); 1950 continue_data.erase(pos_prev_assign + 1, pos_assign - pos_prev_assign - 1); 1951 1952 // We need to add the continue block to all "continue" statements as well 1953 const std::string continue_id = "__CONTINUE__" + std::to_string(continue_block); 1954 for (size_t offset = 0; (offset = loop_data.find(continue_id, offset)) != std::string::npos; offset += continue_data.size()) 1955 loop_data.replace(offset, continue_id.size(), continue_data); 1956 1957 code += "\tbool " + condition_name + ";\n"; 1958 1959 write_location(code, loc); 1960 1961 code += attributes; 1962 code += '\t'; 1963 code += "do\n\t{\n\t\t{\n"; 1964 code += loop_data; // Encapsulate loop body into another scope, so not to confuse any local variables with the current iteration variable accessed in the continue block below 1965 code += "\t\t}\n"; 1966 code += continue_data; 1967 code += "\t}\n\twhile (" + condition_name + ");\n"; 1968 } 1969 else 1970 { 1971 std::string &condition_data = _blocks.at(condition_block); 1972 1973 // If the condition data is just a single line, then it is a simple expression, which we can just put into the loop condition as-is 1974 if (std::count(condition_data.begin(), condition_data.end(), '\n') == 1) 1975 { 1976 // Convert SSA variable initializer back to a condition expression 1977 auto pos_assign = condition_data.find('='); 1978 condition_data.erase(0, pos_assign + 2); 1979 auto pos_semicolon = condition_data.rfind(';'); 1980 condition_data.erase(pos_semicolon); 1981 1982 condition_name = std::move(condition_data); 1983 assert(condition_data.empty()); 1984 } 1985 else 1986 { 1987 code += condition_data; 1988 1989 increase_indentation_level(condition_data); 1990 1991 // Convert the last SSA variable initializer to an assignment statement 1992 auto pos_assign = condition_data.rfind(condition_name); 1993 auto pos_prev_assign = condition_data.rfind('\t', pos_assign); 1994 condition_data.erase(pos_prev_assign + 1, pos_assign - pos_prev_assign - 1); 1995 } 1996 1997 const std::string continue_id = "__CONTINUE__" + std::to_string(continue_block); 1998 for (size_t offset = 0; (offset = loop_data.find(continue_id, offset)) != std::string::npos; offset += continue_data.size()) 1999 loop_data.replace(offset, continue_id.size(), continue_data + condition_data); 2000 2001 code += attributes; 2002 code += '\t'; 2003 code += "while (" + condition_name + ")\n\t{\n\t\t{\n"; 2004 code += loop_data; 2005 code += "\t\t}\n"; 2006 code += continue_data; 2007 code += condition_data; 2008 code += "\t}\n"; 2009 2010 _blocks.erase(condition_block); 2011 } 2012 2013 // Remove consumed blocks to save memory 2014 _blocks.erase(prev_block); 2015 _blocks.erase(header_block); 2016 _blocks.erase(loop_block); 2017 _blocks.erase(continue_block); 2018 } 2019 void emit_switch(const location &loc, id selector_value, id selector_block, id default_label, id default_block, const std::vector<id> &case_literal_and_labels, const std::vector<id> &case_blocks, unsigned int) override 2020 { 2021 assert(selector_value != 0 && selector_block != 0 && default_label != 0 && default_block != 0); 2022 assert(case_blocks.size() == case_literal_and_labels.size() / 2); 2023 2024 std::string &code = _blocks.at(_current_block); 2025 2026 code += _blocks.at(selector_block); 2027 2028 write_location(code, loc); 2029 2030 code += "\tswitch (" + id_to_name(selector_value) + ")\n\t{\n"; 2031 2032 std::vector<id> labels = case_literal_and_labels; 2033 for (size_t i = 0; i < labels.size(); i += 2) 2034 { 2035 if (labels[i + 1] == 0) 2036 continue; // Happens if a case was already handled, see below 2037 2038 code += "\tcase " + std::to_string(labels[i]) + ": "; 2039 2040 if (labels[i + 1] == default_label) 2041 { 2042 code += "default: "; 2043 default_label = 0; 2044 } 2045 else 2046 { 2047 for (size_t k = i + 2; k < labels.size(); k += 2) 2048 { 2049 if (labels[k + 1] == 0 || labels[k + 1] != labels[i + 1]) 2050 continue; 2051 2052 code += "case " + std::to_string(labels[k]) + ": "; 2053 labels[k + 1] = 0; 2054 } 2055 } 2056 2057 assert(case_blocks[i / 2] != 0); 2058 std::string &case_data = _blocks.at(case_blocks[i / 2]); 2059 2060 increase_indentation_level(case_data); 2061 2062 code += "{\n"; 2063 code += case_data; 2064 code += "\t}\n"; 2065 } 2066 2067 2068 if (default_label != 0 && default_block != _current_block) 2069 { 2070 std::string &default_data = _blocks.at(default_block); 2071 2072 increase_indentation_level(default_data); 2073 2074 code += "\tdefault: {\n"; 2075 code += default_data; 2076 code += "\t}\n"; 2077 2078 _blocks.erase(default_block); 2079 } 2080 2081 code += "\t}\n"; 2082 2083 // Remove consumed blocks to save memory 2084 _blocks.erase(selector_block); 2085 for (const id case_block : case_blocks) 2086 _blocks.erase(case_block); 2087 } 2088 2089 id create_block() override 2090 { 2091 const id res = make_id(); 2092 2093 std::string &block = _blocks.emplace(res, std::string()).first->second; 2094 // Reserve a decently big enough memory block to avoid frequent reallocations 2095 block.reserve(4096); 2096 2097 return res; 2098 } 2099 id set_block(id id) override 2100 { 2101 _last_block = _current_block; 2102 _current_block = id; 2103 2104 return _last_block; 2105 } 2106 void enter_block(id id) override 2107 { 2108 _current_block = id; 2109 } 2110 id leave_block_and_kill() override 2111 { 2112 if (!is_in_block()) 2113 return 0; 2114 2115 std::string &code = _blocks.at(_current_block); 2116 2117 code += "\tdiscard;\n"; 2118 2119 const auto &return_type = _functions.back()->return_type; 2120 if (!return_type.is_void()) 2121 { 2122 // Add a return statement to exit functions in case discard is the last control flow statement 2123 code += "\treturn "; 2124 write_constant(code, return_type, constant()); 2125 code += ";\n"; 2126 } 2127 2128 return set_block(0); 2129 } 2130 id leave_block_and_return(id value) override 2131 { 2132 if (!is_in_block()) 2133 return 0; 2134 2135 // Skip implicit return statement 2136 if (!_functions.back()->return_type.is_void() && value == 0) 2137 return set_block(0); 2138 2139 std::string &code = _blocks.at(_current_block); 2140 2141 code += "\treturn"; 2142 2143 if (value != 0) 2144 code += ' ' + id_to_name(value); 2145 2146 code += ";\n"; 2147 2148 return set_block(0); 2149 } 2150 id leave_block_and_switch(id, id) override 2151 { 2152 if (!is_in_block()) 2153 return _last_block; 2154 2155 return set_block(0); 2156 } 2157 id leave_block_and_branch(id target, unsigned int loop_flow) override 2158 { 2159 if (!is_in_block()) 2160 return _last_block; 2161 2162 std::string &code = _blocks.at(_current_block); 2163 2164 switch (loop_flow) 2165 { 2166 case 1: 2167 code += "\tbreak;\n"; 2168 break; 2169 case 2: // Keep track of continue target block, so we can insert its code here later 2170 code += "__CONTINUE__" + std::to_string(target) + "\tcontinue;\n"; 2171 break; 2172 } 2173 2174 return set_block(0); 2175 } 2176 id leave_block_and_branch_conditional(id, id, id) override 2177 { 2178 if (!is_in_block()) 2179 return _last_block; 2180 2181 return set_block(0); 2182 } 2183 void leave_function() override 2184 { 2185 assert(_last_block != 0); 2186 2187 _blocks.at(0) += "{\n" + _blocks.at(_last_block) + "}\n"; 2188 } 2189 }; 2190 } // namespace 2191 2192 codegen *reshadefx::create_codegen_glsl(bool gles, bool vulkan_semantics, bool debug_info, bool uniforms_to_spec_constants, bool enable_16bit_types, bool flip_vert_y) 2193 { 2194 return new codegen_glsl(gles, vulkan_semantics, debug_info, uniforms_to_spec_constants, enable_16bit_types, flip_vert_y); 2195 }