summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Lioncash2019-05-14 12:18:07 -0400
committerGravatar Lioncash2019-05-20 14:14:44 -0400
commit784d2b6c3d0f3181a79732f576e4ec1ff147a858 (patch)
tree0996bc3480e8f8b16101f60f805a5dc30c20f8d4 /src
parentgl_shader_decompiler: Add AddLine() overload that forwards to fmt (diff)
downloadyuzu-784d2b6c3d0f3181a79732f576e4ec1ff147a858.tar.gz
yuzu-784d2b6c3d0f3181a79732f576e4ec1ff147a858.tar.xz
yuzu-784d2b6c3d0f3181a79732f576e4ec1ff147a858.zip
gl_shader_decompiler: Utilize fmt overload of AddLine() where applicable
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp288
1 files changed, 152 insertions, 136 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 58304285f..7c32e0abc 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -178,17 +178,17 @@ public:
178 DeclareSamplers(); 178 DeclareSamplers();
179 DeclarePhysicalAttributeReader(); 179 DeclarePhysicalAttributeReader();
180 180
181 code.AddLine("void execute_" + suffix + "() {"); 181 code.AddLine("void execute_{}() {{", suffix);
182 ++code.scope; 182 ++code.scope;
183 183
184 // VM's program counter 184 // VM's program counter
185 const auto first_address = ir.GetBasicBlocks().begin()->first; 185 const auto first_address = ir.GetBasicBlocks().begin()->first;
186 code.AddLine("uint jmp_to = " + std::to_string(first_address) + "u;"); 186 code.AddLine("uint jmp_to = {}u;", first_address);
187 187
188 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems 188 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
189 // unlikely that shaders will use 20 nested SSYs and PBKs. 189 // unlikely that shaders will use 20 nested SSYs and PBKs.
190 constexpr u32 FLOW_STACK_SIZE = 20; 190 constexpr u32 FLOW_STACK_SIZE = 20;
191 code.AddLine(fmt::format("uint flow_stack[{}];", FLOW_STACK_SIZE)); 191 code.AddLine("uint flow_stack[{}];", FLOW_STACK_SIZE);
192 code.AddLine("uint flow_stack_top = 0u;"); 192 code.AddLine("uint flow_stack_top = 0u;");
193 193
194 code.AddLine("while (true) {"); 194 code.AddLine("while (true) {");
@@ -198,7 +198,7 @@ public:
198 198
199 for (const auto& pair : ir.GetBasicBlocks()) { 199 for (const auto& pair : ir.GetBasicBlocks()) {
200 const auto [address, bb] = pair; 200 const auto [address, bb] = pair;
201 code.AddLine(fmt::format("case 0x{:x}u: {{", address)); 201 code.AddLine("case 0x{:x}u: {{", address);
202 ++code.scope; 202 ++code.scope;
203 203
204 VisitBlock(bb); 204 VisitBlock(bb);
@@ -252,12 +252,13 @@ private:
252 } 252 }
253 253
254 void DeclareGeometry() { 254 void DeclareGeometry() {
255 if (stage != ShaderStage::Geometry) 255 if (stage != ShaderStage::Geometry) {
256 return; 256 return;
257 }
257 258
258 const auto topology = GetTopologyName(header.common3.output_topology); 259 const auto topology = GetTopologyName(header.common3.output_topology);
259 const auto max_vertices = std::to_string(header.common4.max_output_vertices); 260 const auto max_vertices = header.common4.max_output_vertices.Value();
260 code.AddLine("layout (" + topology + ", max_vertices = " + max_vertices + ") out;"); 261 code.AddLine("layout ({}, max_vertices = {}) out;", topology, max_vertices);
261 code.AddNewLine(); 262 code.AddNewLine();
262 263
263 DeclareVertexRedeclarations(); 264 DeclareVertexRedeclarations();
@@ -289,33 +290,35 @@ private:
289 void DeclareRegisters() { 290 void DeclareRegisters() {
290 const auto& registers = ir.GetRegisters(); 291 const auto& registers = ir.GetRegisters();
291 for (const u32 gpr : registers) { 292 for (const u32 gpr : registers) {
292 code.AddLine("float " + GetRegister(gpr) + " = 0;"); 293 code.AddLine("float {} = 0;", GetRegister(gpr));
293 } 294 }
294 if (!registers.empty()) 295 if (!registers.empty()) {
295 code.AddNewLine(); 296 code.AddNewLine();
297 }
296 } 298 }
297 299
298 void DeclarePredicates() { 300 void DeclarePredicates() {
299 const auto& predicates = ir.GetPredicates(); 301 const auto& predicates = ir.GetPredicates();
300 for (const auto pred : predicates) { 302 for (const auto pred : predicates) {
301 code.AddLine("bool " + GetPredicate(pred) + " = false;"); 303 code.AddLine("bool {} = false;", GetPredicate(pred));
302 } 304 }
303 if (!predicates.empty()) 305 if (!predicates.empty()) {
304 code.AddNewLine(); 306 code.AddNewLine();
307 }
305 } 308 }
306 309
307 void DeclareLocalMemory() { 310 void DeclareLocalMemory() {
308 if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) { 311 if (const u64 local_memory_size = header.GetLocalMemorySize(); local_memory_size > 0) {
309 const auto element_count = Common::AlignUp(local_memory_size, 4) / 4; 312 const auto element_count = Common::AlignUp(local_memory_size, 4) / 4;
310 code.AddLine("float " + GetLocalMemory() + '[' + std::to_string(element_count) + "];"); 313 code.AddLine("float {}[{}];", GetLocalMemory(), element_count);
311 code.AddNewLine(); 314 code.AddNewLine();
312 } 315 }
313 } 316 }
314 317
315 void DeclareInternalFlags() { 318 void DeclareInternalFlags() {
316 for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) { 319 for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) {
317 const InternalFlag flag_code = static_cast<InternalFlag>(flag); 320 const auto flag_code = static_cast<InternalFlag>(flag);
318 code.AddLine("bool " + GetInternalFlag(flag_code) + " = false;"); 321 code.AddLine("bool {} = false;", GetInternalFlag(flag_code));
319 } 322 }
320 code.AddNewLine(); 323 code.AddNewLine();
321 } 324 }
@@ -354,8 +357,9 @@ private:
354 DeclareInputAttribute(index, false); 357 DeclareInputAttribute(index, false);
355 } 358 }
356 } 359 }
357 if (!attributes.empty()) 360 if (!attributes.empty()) {
358 code.AddNewLine(); 361 code.AddNewLine();
362 }
359 } 363 }
360 364
361 void DeclareInputAttribute(Attribute::Index index, bool skip_unused) { 365 void DeclareInputAttribute(Attribute::Index index, bool skip_unused) {
@@ -381,8 +385,7 @@ private:
381 location += GENERIC_VARYING_START_LOCATION; 385 location += GENERIC_VARYING_START_LOCATION;
382 } 386 }
383 387
384 code.AddLine("layout (location = " + std::to_string(location) + ") " + suffix + "in vec4 " + 388 code.AddLine("layout (location = {}) {} in vec4 {};", name, location, suffix, name);
385 name + ';');
386 } 389 }
387 390
388 void DeclareOutputAttributes() { 391 void DeclareOutputAttributes() {
@@ -400,22 +403,22 @@ private:
400 DeclareOutputAttribute(index); 403 DeclareOutputAttribute(index);
401 } 404 }
402 } 405 }
403 if (!attributes.empty()) 406 if (!attributes.empty()) {
404 code.AddNewLine(); 407 code.AddNewLine();
408 }
405 } 409 }
406 410
407 void DeclareOutputAttribute(Attribute::Index index) { 411 void DeclareOutputAttribute(Attribute::Index index) {
408 const u32 location{GetGenericAttributeIndex(index) + GENERIC_VARYING_START_LOCATION}; 412 const u32 location{GetGenericAttributeIndex(index) + GENERIC_VARYING_START_LOCATION};
409 code.AddLine("layout (location = " + std::to_string(location) + ") out vec4 " + 413 code.AddLine("layout (location = {}) out vec4 {};", location, GetOutputAttribute(index));
410 GetOutputAttribute(index) + ';');
411 } 414 }
412 415
413 void DeclareConstantBuffers() { 416 void DeclareConstantBuffers() {
414 for (const auto& entry : ir.GetConstantBuffers()) { 417 for (const auto& entry : ir.GetConstantBuffers()) {
415 const auto [index, size] = entry; 418 const auto [index, size] = entry;
416 code.AddLine("layout (std140, binding = CBUF_BINDING_" + std::to_string(index) + 419 code.AddLine("layout (std140, binding = CBUF_BINDING_{}) uniform {} {{", index,
417 ") uniform " + GetConstBufferBlock(index) + " {"); 420 GetConstBufferBlock(index));
418 code.AddLine(" vec4 " + GetConstBuffer(index) + "[MAX_CONSTBUFFER_ELEMENTS];"); 421 code.AddLine(" vec4 {}[MAX_CONSTBUFFER_ELEMENTS];", GetConstBuffer(index));
419 code.AddLine("};"); 422 code.AddLine("};");
420 code.AddNewLine(); 423 code.AddNewLine();
421 } 424 }
@@ -428,16 +431,15 @@ private:
428 // Since we don't know how the shader will use the shader, hint the driver to disable as 431 // Since we don't know how the shader will use the shader, hint the driver to disable as
429 // much optimizations as possible 432 // much optimizations as possible
430 std::string qualifier = "coherent volatile"; 433 std::string qualifier = "coherent volatile";
431 if (usage.is_read && !usage.is_written) 434 if (usage.is_read && !usage.is_written) {
432 qualifier += " readonly"; 435 qualifier += " readonly";
433 else if (usage.is_written && !usage.is_read) 436 } else if (usage.is_written && !usage.is_read) {
434 qualifier += " writeonly"; 437 qualifier += " writeonly";
438 }
435 439
436 const std::string binding = 440 code.AddLine("layout (std430, binding = GMEM_BINDING_{}_{}) {} buffer {} {{",
437 fmt::format("GMEM_BINDING_{}_{}", base.cbuf_index, base.cbuf_offset); 441 base.cbuf_index, base.cbuf_offset, qualifier, GetGlobalMemoryBlock(base));
438 code.AddLine("layout (std430, binding = " + binding + ") " + qualifier + " buffer " + 442 code.AddLine(" float {}[];", GetGlobalMemory(base));
439 GetGlobalMemoryBlock(base) + " {");
440 code.AddLine(" float " + GetGlobalMemory(base) + "[];");
441 code.AddLine("};"); 443 code.AddLine("};");
442 code.AddNewLine(); 444 code.AddNewLine();
443 } 445 }
@@ -446,7 +448,7 @@ private:
446 void DeclareSamplers() { 448 void DeclareSamplers() {
447 const auto& samplers = ir.GetSamplers(); 449 const auto& samplers = ir.GetSamplers();
448 for (const auto& sampler : samplers) { 450 for (const auto& sampler : samplers) {
449 std::string sampler_type = [&]() { 451 std::string sampler_type = [&sampler] {
450 switch (sampler.GetType()) { 452 switch (sampler.GetType()) {
451 case Tegra::Shader::TextureType::Texture1D: 453 case Tegra::Shader::TextureType::Texture1D:
452 return "sampler1D"; 454 return "sampler1D";
@@ -461,25 +463,28 @@ private:
461 return "sampler2D"; 463 return "sampler2D";
462 } 464 }
463 }(); 465 }();
464 if (sampler.IsArray()) 466 if (sampler.IsArray()) {
465 sampler_type += "Array"; 467 sampler_type += "Array";
466 if (sampler.IsShadow()) 468 }
469 if (sampler.IsShadow()) {
467 sampler_type += "Shadow"; 470 sampler_type += "Shadow";
471 }
468 472
469 code.AddLine("layout (binding = SAMPLER_BINDING_" + std::to_string(sampler.GetIndex()) + 473 code.AddLine("layout (binding = SAMPLER_BINDING_{}) uniform {} {};", sampler.GetIndex(),
470 ") uniform " + sampler_type + ' ' + GetSampler(sampler) + ';'); 474 sampler_type, GetSampler(sampler));
471 } 475 }
472 if (!samplers.empty()) 476 if (!samplers.empty()) {
473 code.AddNewLine(); 477 code.AddNewLine();
478 }
474 } 479 }
475 480
476 void DeclarePhysicalAttributeReader() { 481 void DeclarePhysicalAttributeReader() {
477 if (!ir.HasPhysicalAttributes()) { 482 if (!ir.HasPhysicalAttributes()) {
478 return; 483 return;
479 } 484 }
480 code.AddLine("float readPhysicalAttribute(uint physical_address) {"); 485 code.AddLine("float readPhysicalAttribute(uint physical_address) {{");
481 ++code.scope; 486 ++code.scope;
482 code.AddLine("switch (physical_address) {"); 487 code.AddLine("switch (physical_address) {{");
483 488
484 // Just declare generic attributes for now. 489 // Just declare generic attributes for now.
485 const auto num_attributes{static_cast<u32>(GetNumPhysicalInputAttributes())}; 490 const auto num_attributes{static_cast<u32>(GetNumPhysicalInputAttributes())};
@@ -494,15 +499,15 @@ private:
494 const bool declared{stage != ShaderStage::Fragment || 499 const bool declared{stage != ShaderStage::Fragment ||
495 header.ps.GetAttributeUse(index) != AttributeUse::Unused}; 500 header.ps.GetAttributeUse(index) != AttributeUse::Unused};
496 const std::string value{declared ? ReadAttribute(attribute, element) : "0"}; 501 const std::string value{declared ? ReadAttribute(attribute, element) : "0"};
497 code.AddLine(fmt::format("case 0x{:x}: return {};", address, value)); 502 code.AddLine("case 0x{:x}: return {};", address, value);
498 } 503 }
499 } 504 }
500 505
501 code.AddLine("default: return 0;"); 506 code.AddLine("default: return 0;");
502 507
503 code.AddLine('}'); 508 code.AddLine("}}");
504 --code.scope; 509 --code.scope;
505 code.AddLine('}'); 510 code.AddLine("}}");
506 code.AddNewLine(); 511 code.AddNewLine();
507 } 512 }
508 513
@@ -527,23 +532,26 @@ private:
527 return {}; 532 return {};
528 } 533 }
529 return (this->*decompiler)(*operation); 534 return (this->*decompiler)(*operation);
535 }
530 536
531 } else if (const auto gpr = std::get_if<GprNode>(node)) { 537 if (const auto gpr = std::get_if<GprNode>(node)) {
532 const u32 index = gpr->GetIndex(); 538 const u32 index = gpr->GetIndex();
533 if (index == Register::ZeroIndex) { 539 if (index == Register::ZeroIndex) {
534 return "0"; 540 return "0";
535 } 541 }
536 return GetRegister(index); 542 return GetRegister(index);
543 }
537 544
538 } else if (const auto immediate = std::get_if<ImmediateNode>(node)) { 545 if (const auto immediate = std::get_if<ImmediateNode>(node)) {
539 const u32 value = immediate->GetValue(); 546 const u32 value = immediate->GetValue();
540 if (value < 10) { 547 if (value < 10) {
541 // For eyecandy avoid using hex numbers on single digits 548 // For eyecandy avoid using hex numbers on single digits
542 return fmt::format("utof({}u)", immediate->GetValue()); 549 return fmt::format("utof({}u)", immediate->GetValue());
543 } 550 }
544 return fmt::format("utof(0x{:x}u)", immediate->GetValue()); 551 return fmt::format("utof(0x{:x}u)", immediate->GetValue());
552 }
545 553
546 } else if (const auto predicate = std::get_if<PredicateNode>(node)) { 554 if (const auto predicate = std::get_if<PredicateNode>(node)) {
547 const auto value = [&]() -> std::string { 555 const auto value = [&]() -> std::string {
548 switch (const auto index = predicate->GetIndex(); index) { 556 switch (const auto index = predicate->GetIndex(); index) {
549 case Tegra::Shader::Pred::UnusedIndex: 557 case Tegra::Shader::Pred::UnusedIndex:
@@ -555,19 +563,22 @@ private:
555 } 563 }
556 }(); 564 }();
557 if (predicate->IsNegated()) { 565 if (predicate->IsNegated()) {
558 return "!(" + value + ')'; 566 return fmt::format("!({})", value);
559 } 567 }
560 return value; 568 return value;
569 }
561 570
562 } else if (const auto abuf = std::get_if<AbufNode>(node)) { 571 if (const auto abuf = std::get_if<AbufNode>(node)) {
563 UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, 572 UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry,
564 "Physical attributes in geometry shaders are not implemented"); 573 "Physical attributes in geometry shaders are not implemented");
565 if (abuf->IsPhysicalBuffer()) { 574 if (abuf->IsPhysicalBuffer()) {
566 return "readPhysicalAttribute(ftou(" + Visit(abuf->GetPhysicalAddress()) + "))"; 575 return fmt::format("readPhysicalAttribute(ftou({}))",
576 Visit(abuf->GetPhysicalAddress()));
567 } 577 }
568 return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); 578 return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer());
579 }
569 580
570 } else if (const auto cbuf = std::get_if<CbufNode>(node)) { 581 if (const auto cbuf = std::get_if<CbufNode>(node)) {
571 const Node offset = cbuf->GetOffset(); 582 const Node offset = cbuf->GetOffset();
572 if (const auto immediate = std::get_if<ImmediateNode>(offset)) { 583 if (const auto immediate = std::get_if<ImmediateNode>(offset)) {
573 // Direct access 584 // Direct access
@@ -575,33 +586,37 @@ private:
575 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); 586 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access");
576 return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()), 587 return fmt::format("{}[{}][{}]", GetConstBuffer(cbuf->GetIndex()),
577 offset_imm / (4 * 4), (offset_imm / 4) % 4); 588 offset_imm / (4 * 4), (offset_imm / 4) % 4);
589 }
578 590
579 } else if (std::holds_alternative<OperationNode>(*offset)) { 591 if (std::holds_alternative<OperationNode>(*offset)) {
580 // Indirect access 592 // Indirect access
581 const std::string final_offset = code.GenerateTemporary(); 593 const std::string final_offset = code.GenerateTemporary();
582 code.AddLine("uint " + final_offset + " = (ftou(" + Visit(offset) + ") / 4);"); 594 code.AddLine("uint {} = (ftou({}) / 4);", final_offset, Visit(offset));
583 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()), 595 return fmt::format("{}[{} / 4][{} % 4]", GetConstBuffer(cbuf->GetIndex()),
584 final_offset, final_offset); 596 final_offset, final_offset);
585
586 } else {
587 UNREACHABLE_MSG("Unmanaged offset node type");
588 } 597 }
589 598
590 } else if (const auto gmem = std::get_if<GmemNode>(node)) { 599 UNREACHABLE_MSG("Unmanaged offset node type");
600 }
601
602 if (const auto gmem = std::get_if<GmemNode>(node)) {
591 const std::string real = Visit(gmem->GetRealAddress()); 603 const std::string real = Visit(gmem->GetRealAddress());
592 const std::string base = Visit(gmem->GetBaseAddress()); 604 const std::string base = Visit(gmem->GetBaseAddress());
593 const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; 605 const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base);
594 return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); 606 return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset);
607 }
595 608
596 } else if (const auto lmem = std::get_if<LmemNode>(node)) { 609 if (const auto lmem = std::get_if<LmemNode>(node)) {
597 return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); 610 return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
611 }
598 612
599 } else if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { 613 if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) {
600 return GetInternalFlag(internal_flag->GetFlag()); 614 return GetInternalFlag(internal_flag->GetFlag());
615 }
601 616
602 } else if (const auto conditional = std::get_if<ConditionalNode>(node)) { 617 if (const auto conditional = std::get_if<ConditionalNode>(node)) {
603 // It's invalid to call conditional on nested nodes, use an operation instead 618 // It's invalid to call conditional on nested nodes, use an operation instead
604 code.AddLine("if (" + Visit(conditional->GetCondition()) + ") {"); 619 code.AddLine("if ({}) {{", Visit(conditional->GetCondition()));
605 ++code.scope; 620 ++code.scope;
606 621
607 VisitBlock(conditional->GetCode()); 622 VisitBlock(conditional->GetCode());
@@ -609,23 +624,25 @@ private:
609 --code.scope; 624 --code.scope;
610 code.AddLine('}'); 625 code.AddLine('}');
611 return {}; 626 return {};
627 }
612 628
613 } else if (const auto comment = std::get_if<CommentNode>(node)) { 629 if (const auto comment = std::get_if<CommentNode>(node)) {
614 return "// " + comment->GetText(); 630 return "// " + comment->GetText();
615 } 631 }
632
616 UNREACHABLE(); 633 UNREACHABLE();
617 return {}; 634 return {};
618 } 635 }
619 636
620 std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { 637 std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) {
621 const auto GeometryPass = [&](std::string name) { 638 const auto GeometryPass = [&](std::string_view name) {
622 if (stage == ShaderStage::Geometry && buffer) { 639 if (stage == ShaderStage::Geometry && buffer) {
623 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games 640 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
624 // set an 0x80000000 index for those and the shader fails to build. Find out why 641 // set an 0x80000000 index for those and the shader fails to build. Find out why
625 // this happens and what's its intent. 642 // this happens and what's its intent.
626 return "gs_" + std::move(name) + "[ftou(" + Visit(buffer) + ") % MAX_VERTEX_INPUT]"; 643 return fmt::format("gs_{}[ftou({}) % MAX_VERTEX_INPUT]", name, Visit(buffer));
627 } 644 }
628 return name; 645 return std::string(name);
629 }; 646 };
630 647
631 switch (attribute) { 648 switch (attribute) {
@@ -688,7 +705,7 @@ private:
688 const std::string precise = stage != ShaderStage::Fragment ? "precise " : ""; 705 const std::string precise = stage != ShaderStage::Fragment ? "precise " : "";
689 706
690 const std::string temporary = code.GenerateTemporary(); 707 const std::string temporary = code.GenerateTemporary();
691 code.AddLine(precise + "float " + temporary + " = " + value + ';'); 708 code.AddLine("{}float {} = {};", precise, temporary, value);
692 return temporary; 709 return temporary;
693 } 710 }
694 711
@@ -702,7 +719,7 @@ private:
702 } 719 }
703 720
704 const std::string temporary = code.GenerateTemporary(); 721 const std::string temporary = code.GenerateTemporary();
705 code.AddLine("float " + temporary + " = " + Visit(operand) + ';'); 722 code.AddLine("float {} = {};", temporary, Visit(operand));
706 return temporary; 723 return temporary;
707 } 724 }
708 725
@@ -717,31 +734,32 @@ private:
717 case Type::Float: 734 case Type::Float:
718 return value; 735 return value;
719 case Type::Int: 736 case Type::Int:
720 return "ftoi(" + value + ')'; 737 return fmt::format("ftoi({})", value);
721 case Type::Uint: 738 case Type::Uint:
722 return "ftou(" + value + ')'; 739 return fmt::format("ftou({})", value);
723 case Type::HalfFloat: 740 case Type::HalfFloat:
724 return "toHalf2(" + value + ')'; 741 return fmt::format("toHalf2({})", value);
725 } 742 }
726 UNREACHABLE(); 743 UNREACHABLE();
727 return value; 744 return value;
728 } 745 }
729 746
730 std::string BitwiseCastResult(std::string value, Type type, bool needs_parenthesis = false) { 747 std::string BitwiseCastResult(const std::string& value, Type type,
748 bool needs_parenthesis = false) {
731 switch (type) { 749 switch (type) {
732 case Type::Bool: 750 case Type::Bool:
733 case Type::Bool2: 751 case Type::Bool2:
734 case Type::Float: 752 case Type::Float:
735 if (needs_parenthesis) { 753 if (needs_parenthesis) {
736 return '(' + value + ')'; 754 return fmt::format("({})", value);
737 } 755 }
738 return value; 756 return value;
739 case Type::Int: 757 case Type::Int:
740 return "itof(" + value + ')'; 758 return fmt::format("itof({})", value);
741 case Type::Uint: 759 case Type::Uint:
742 return "utof(" + value + ')'; 760 return fmt::format("utof({})", value);
743 case Type::HalfFloat: 761 case Type::HalfFloat:
744 return "fromHalf2(" + value + ')'; 762 return fmt::format("fromHalf2({})", value);
745 } 763 }
746 UNREACHABLE(); 764 UNREACHABLE();
747 return value; 765 return value;
@@ -749,27 +767,27 @@ private:
749 767
750 std::string GenerateUnary(Operation operation, const std::string& func, Type result_type, 768 std::string GenerateUnary(Operation operation, const std::string& func, Type result_type,
751 Type type_a, bool needs_parenthesis = true) { 769 Type type_a, bool needs_parenthesis = true) {
752 return ApplyPrecise(operation, 770 const std::string op_str = fmt::format("{}({})", func, VisitOperand(operation, 0, type_a));
753 BitwiseCastResult(func + '(' + VisitOperand(operation, 0, type_a) + ')', 771
754 result_type, needs_parenthesis)); 772 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type, needs_parenthesis));
755 } 773 }
756 774
757 std::string GenerateBinaryInfix(Operation operation, const std::string& func, Type result_type, 775 std::string GenerateBinaryInfix(Operation operation, const std::string& func, Type result_type,
758 Type type_a, Type type_b) { 776 Type type_a, Type type_b) {
759 const std::string op_a = VisitOperand(operation, 0, type_a); 777 const std::string op_a = VisitOperand(operation, 0, type_a);
760 const std::string op_b = VisitOperand(operation, 1, type_b); 778 const std::string op_b = VisitOperand(operation, 1, type_b);
779 const std::string op_str = fmt::format("({} {} {})", op_a, func, op_b);
761 780
762 return ApplyPrecise( 781 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type));
763 operation, BitwiseCastResult('(' + op_a + ' ' + func + ' ' + op_b + ')', result_type));
764 } 782 }
765 783
766 std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type, 784 std::string GenerateBinaryCall(Operation operation, const std::string& func, Type result_type,
767 Type type_a, Type type_b) { 785 Type type_a, Type type_b) {
768 const std::string op_a = VisitOperand(operation, 0, type_a); 786 const std::string op_a = VisitOperand(operation, 0, type_a);
769 const std::string op_b = VisitOperand(operation, 1, type_b); 787 const std::string op_b = VisitOperand(operation, 1, type_b);
788 const std::string op_str = fmt::format("{}({}, {})", func, op_a, op_b);
770 789
771 return ApplyPrecise(operation, 790 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type));
772 BitwiseCastResult(func + '(' + op_a + ", " + op_b + ')', result_type));
773 } 791 }
774 792
775 std::string GenerateTernary(Operation operation, const std::string& func, Type result_type, 793 std::string GenerateTernary(Operation operation, const std::string& func, Type result_type,
@@ -777,10 +795,9 @@ private:
777 const std::string op_a = VisitOperand(operation, 0, type_a); 795 const std::string op_a = VisitOperand(operation, 0, type_a);
778 const std::string op_b = VisitOperand(operation, 1, type_b); 796 const std::string op_b = VisitOperand(operation, 1, type_b);
779 const std::string op_c = VisitOperand(operation, 2, type_c); 797 const std::string op_c = VisitOperand(operation, 2, type_c);
798 const std::string op_str = fmt::format("{}({}, {}, {})", func, op_a, op_b, op_c);
780 799
781 return ApplyPrecise( 800 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type));
782 operation,
783 BitwiseCastResult(func + '(' + op_a + ", " + op_b + ", " + op_c + ')', result_type));
784 } 801 }
785 802
786 std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type, 803 std::string GenerateQuaternary(Operation operation, const std::string& func, Type result_type,
@@ -789,10 +806,9 @@ private:
789 const std::string op_b = VisitOperand(operation, 1, type_b); 806 const std::string op_b = VisitOperand(operation, 1, type_b);
790 const std::string op_c = VisitOperand(operation, 2, type_c); 807 const std::string op_c = VisitOperand(operation, 2, type_c);
791 const std::string op_d = VisitOperand(operation, 3, type_d); 808 const std::string op_d = VisitOperand(operation, 3, type_d);
809 const std::string op_str = fmt::format("{}({}, {}, {}, {})", func, op_a, op_b, op_c, op_d);
792 810
793 return ApplyPrecise(operation, BitwiseCastResult(func + '(' + op_a + ", " + op_b + ", " + 811 return ApplyPrecise(operation, BitwiseCastResult(op_str, result_type));
794 op_c + ", " + op_d + ')',
795 result_type));
796 } 812 }
797 813
798 std::string GenerateTexture(Operation operation, const std::string& function_suffix, 814 std::string GenerateTexture(Operation operation, const std::string& function_suffix,
@@ -855,7 +871,7 @@ private:
855 // required to be constant) 871 // required to be constant)
856 expr += std::to_string(static_cast<s32>(immediate->GetValue())); 872 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
857 } else { 873 } else {
858 expr += "ftoi(" + Visit(operand) + ')'; 874 expr += fmt::format("ftoi({})", Visit(operand));
859 } 875 }
860 break; 876 break;
861 case Type::Float: 877 case Type::Float:
@@ -888,7 +904,7 @@ private:
888 expr += std::to_string(static_cast<s32>(immediate->GetValue())); 904 expr += std::to_string(static_cast<s32>(immediate->GetValue()));
889 } else if (device.HasVariableAoffi()) { 905 } else if (device.HasVariableAoffi()) {
890 // Avoid using variable AOFFI on unsupported devices. 906 // Avoid using variable AOFFI on unsupported devices.
891 expr += "ftoi(" + Visit(operand) + ')'; 907 expr += fmt::format("ftoi({})", Visit(operand));
892 } else { 908 } else {
893 // Insert 0 on devices not supporting variable AOFFI. 909 // Insert 0 on devices not supporting variable AOFFI.
894 expr += '0'; 910 expr += '0';
@@ -913,7 +929,6 @@ private:
913 return {}; 929 return {};
914 } 930 }
915 target = GetRegister(gpr->GetIndex()); 931 target = GetRegister(gpr->GetIndex());
916
917 } else if (const auto abuf = std::get_if<AbufNode>(dest)) { 932 } else if (const auto abuf = std::get_if<AbufNode>(dest)) {
918 UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); 933 UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer());
919 934
@@ -924,9 +939,9 @@ private:
924 case Attribute::Index::PointSize: 939 case Attribute::Index::PointSize:
925 return "gl_PointSize"; 940 return "gl_PointSize";
926 case Attribute::Index::ClipDistances0123: 941 case Attribute::Index::ClipDistances0123:
927 return "gl_ClipDistance[" + std::to_string(abuf->GetElement()) + ']'; 942 return fmt::format("gl_ClipDistance[{}]", abuf->GetElement());
928 case Attribute::Index::ClipDistances4567: 943 case Attribute::Index::ClipDistances4567:
929 return "gl_ClipDistance[" + std::to_string(abuf->GetElement() + 4) + ']'; 944 return fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4);
930 default: 945 default:
931 if (IsGenericAttribute(attribute)) { 946 if (IsGenericAttribute(attribute)) {
932 return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); 947 return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement());
@@ -936,21 +951,18 @@ private:
936 return "0"; 951 return "0";
937 } 952 }
938 }(); 953 }();
939
940 } else if (const auto lmem = std::get_if<LmemNode>(dest)) { 954 } else if (const auto lmem = std::get_if<LmemNode>(dest)) {
941 target = GetLocalMemory() + "[ftou(" + Visit(lmem->GetAddress()) + ") / 4]"; 955 target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
942
943 } else if (const auto gmem = std::get_if<GmemNode>(dest)) { 956 } else if (const auto gmem = std::get_if<GmemNode>(dest)) {
944 const std::string real = Visit(gmem->GetRealAddress()); 957 const std::string real = Visit(gmem->GetRealAddress());
945 const std::string base = Visit(gmem->GetBaseAddress()); 958 const std::string base = Visit(gmem->GetBaseAddress());
946 const std::string final_offset = "(ftou(" + real + ") - ftou(" + base + ")) / 4"; 959 const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base);
947 target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); 960 target = fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset);
948
949 } else { 961 } else {
950 UNREACHABLE_MSG("Assign called without a proper target"); 962 UNREACHABLE_MSG("Assign called without a proper target");
951 } 963 }
952 964
953 code.AddLine(target + " = " + Visit(src) + ';'); 965 code.AddLine("{} = {};", target, Visit(src));
954 return {}; 966 return {};
955 } 967 }
956 968
@@ -1003,8 +1015,9 @@ private:
1003 const std::string condition = Visit(operation[0]); 1015 const std::string condition = Visit(operation[0]);
1004 const std::string true_case = Visit(operation[1]); 1016 const std::string true_case = Visit(operation[1]);
1005 const std::string false_case = Visit(operation[2]); 1017 const std::string false_case = Visit(operation[2]);
1006 return ApplyPrecise(operation, 1018 const std::string op_str = fmt::format("({} ? {} : {})", condition, true_case, false_case);
1007 '(' + condition + " ? " + true_case + " : " + false_case + ')'); 1019
1020 return ApplyPrecise(operation, op_str);
1008 } 1021 }
1009 1022
1010 std::string FCos(Operation operation) { 1023 std::string FCos(Operation operation) {
@@ -1068,9 +1081,9 @@ private:
1068 std::string ILogicalShiftRight(Operation operation) { 1081 std::string ILogicalShiftRight(Operation operation) {
1069 const std::string op_a = VisitOperand(operation, 0, Type::Uint); 1082 const std::string op_a = VisitOperand(operation, 0, Type::Uint);
1070 const std::string op_b = VisitOperand(operation, 1, Type::Uint); 1083 const std::string op_b = VisitOperand(operation, 1, Type::Uint);
1084 const std::string op_str = fmt::format("int({} >> {})", op_a, op_b);
1071 1085
1072 return ApplyPrecise(operation, 1086 return ApplyPrecise(operation, BitwiseCastResult(op_str, Type::Int));
1073 BitwiseCastResult("int(" + op_a + " >> " + op_b + ')', Type::Int));
1074 } 1087 }
1075 1088
1076 std::string IArithmeticShiftRight(Operation operation) { 1089 std::string IArithmeticShiftRight(Operation operation) {
@@ -1126,11 +1139,12 @@ private:
1126 } 1139 }
1127 1140
1128 std::string HNegate(Operation operation) { 1141 std::string HNegate(Operation operation) {
1129 const auto GetNegate = [&](std::size_t index) -> std::string { 1142 const auto GetNegate = [&](std::size_t index) {
1130 return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1"; 1143 return VisitOperand(operation, index, Type::Bool) + " ? -1 : 1";
1131 }; 1144 };
1132 const std::string value = '(' + VisitOperand(operation, 0, Type::HalfFloat) + " * vec2(" + 1145 const std::string value =
1133 GetNegate(1) + ", " + GetNegate(2) + "))"; 1146 fmt::format("({} * vec2({}, {}))", VisitOperand(operation, 0, Type::HalfFloat),
1147 GetNegate(1), GetNegate(2));
1134 return BitwiseCastResult(value, Type::HalfFloat); 1148 return BitwiseCastResult(value, Type::HalfFloat);
1135 } 1149 }
1136 1150
@@ -1138,7 +1152,8 @@ private:
1138 const std::string value = VisitOperand(operation, 0, Type::HalfFloat); 1152 const std::string value = VisitOperand(operation, 0, Type::HalfFloat);
1139 const std::string min = VisitOperand(operation, 1, Type::Float); 1153 const std::string min = VisitOperand(operation, 1, Type::Float);
1140 const std::string max = VisitOperand(operation, 2, Type::Float); 1154 const std::string max = VisitOperand(operation, 2, Type::Float);
1141 const std::string clamped = "clamp(" + value + ", vec2(" + min + "), vec2(" + max + "))"; 1155 const std::string clamped = fmt::format("clamp({}, vec2({}), vec2({}))", value, min, max);
1156
1142 return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat)); 1157 return ApplyPrecise(operation, BitwiseCastResult(clamped, Type::HalfFloat));
1143 } 1158 }
1144 1159
@@ -1149,34 +1164,35 @@ private:
1149 case Tegra::Shader::HalfType::H0_H1: 1164 case Tegra::Shader::HalfType::H0_H1:
1150 return operand; 1165 return operand;
1151 case Tegra::Shader::HalfType::F32: 1166 case Tegra::Shader::HalfType::F32:
1152 return "vec2(fromHalf2(" + operand + "))"; 1167 return fmt::format("vec2(fromHalf2({}))", operand);
1153 case Tegra::Shader::HalfType::H0_H0: 1168 case Tegra::Shader::HalfType::H0_H0:
1154 return "vec2(" + operand + "[0])"; 1169 return fmt::format("vec2({}[0])", operand);
1155 case Tegra::Shader::HalfType::H1_H1: 1170 case Tegra::Shader::HalfType::H1_H1:
1156 return "vec2(" + operand + "[1])"; 1171 return fmt::format("vec2({}[1])", operand);
1157 } 1172 }
1158 UNREACHABLE(); 1173 UNREACHABLE();
1159 return "0"; 1174 return "0";
1160 }(); 1175 }();
1161 return "fromHalf2(" + value + ')'; 1176 return fmt::format("fromHalf2({})", value);
1162 } 1177 }
1163 1178
1164 std::string HMergeF32(Operation operation) { 1179 std::string HMergeF32(Operation operation) {
1165 return "float(toHalf2(" + Visit(operation[0]) + ")[0])"; 1180 return fmt::format("float(toHalf2({})[0])", Visit(operation[0]));
1166 } 1181 }
1167 1182
1168 std::string HMergeH0(Operation operation) { 1183 std::string HMergeH0(Operation operation) {
1169 return "fromHalf2(vec2(toHalf2(" + Visit(operation[1]) + ")[0], toHalf2(" + 1184 return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[1]),
1170 Visit(operation[0]) + ")[1]))"; 1185 Visit(operation[0]));
1171 } 1186 }
1172 1187
1173 std::string HMergeH1(Operation operation) { 1188 std::string HMergeH1(Operation operation) {
1174 return "fromHalf2(vec2(toHalf2(" + Visit(operation[0]) + ")[0], toHalf2(" + 1189 return fmt::format("fromHalf2(vec2(toHalf2({})[0], toHalf2({})[1]))", Visit(operation[0]),
1175 Visit(operation[1]) + ")[1]))"; 1190 Visit(operation[1]));
1176 } 1191 }
1177 1192
1178 std::string HPack2(Operation operation) { 1193 std::string HPack2(Operation operation) {
1179 return "utof(packHalf2x16(vec2(" + Visit(operation[0]) + ", " + Visit(operation[1]) + ")))"; 1194 return fmt::format("utof(packHalf2x16(vec2({}, {})))", Visit(operation[0]),
1195 Visit(operation[1]));
1180 } 1196 }
1181 1197
1182 template <Type type> 1198 template <Type type>
@@ -1234,7 +1250,7 @@ private:
1234 target = GetInternalFlag(flag->GetFlag()); 1250 target = GetInternalFlag(flag->GetFlag());
1235 } 1251 }
1236 1252
1237 code.AddLine(target + " = " + Visit(src) + ';'); 1253 code.AddLine("{} = {};", target, Visit(src));
1238 return {}; 1254 return {};
1239 } 1255 }
1240 1256
@@ -1256,7 +1272,7 @@ private:
1256 1272
1257 std::string LogicalPick2(Operation operation) { 1273 std::string LogicalPick2(Operation operation) {
1258 const std::string pair = VisitOperand(operation, 0, Type::Bool2); 1274 const std::string pair = VisitOperand(operation, 0, Type::Bool2);
1259 return pair + '[' + VisitOperand(operation, 1, Type::Uint) + ']'; 1275 return fmt::format("{}[{}]", pair, VisitOperand(operation, 1, Type::Uint));
1260 } 1276 }
1261 1277
1262 std::string LogicalAll2(Operation operation) { 1278 std::string LogicalAll2(Operation operation) {
@@ -1268,15 +1284,15 @@ private:
1268 } 1284 }
1269 1285
1270 template <bool with_nan> 1286 template <bool with_nan>
1271 std::string GenerateHalfComparison(Operation operation, std::string compare_op) { 1287 std::string GenerateHalfComparison(Operation operation, const std::string& compare_op) {
1272 std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2, 1288 const std::string comparison{GenerateBinaryCall(operation, compare_op, Type::Bool2,
1273 Type::HalfFloat, Type::HalfFloat)}; 1289 Type::HalfFloat, Type::HalfFloat)};
1274 if constexpr (!with_nan) { 1290 if constexpr (!with_nan) {
1275 return comparison; 1291 return comparison;
1276 } 1292 }
1277 return "halfFloatNanComparison(" + comparison + ", " + 1293 return fmt::format("halfFloatNanComparison({}, {}, {})", comparison,
1278 VisitOperand(operation, 0, Type::HalfFloat) + ", " + 1294 VisitOperand(operation, 0, Type::HalfFloat),
1279 VisitOperand(operation, 1, Type::HalfFloat) + ')'; 1295 VisitOperand(operation, 1, Type::HalfFloat));
1280 } 1296 }
1281 1297
1282 template <bool with_nan> 1298 template <bool with_nan>
@@ -1353,12 +1369,12 @@ private:
1353 switch (meta->element) { 1369 switch (meta->element) {
1354 case 0: 1370 case 0:
1355 case 1: 1371 case 1:
1356 return "itof(int(textureSize(" + sampler + ", " + lod + ')' + 1372 return fmt::format("itof(int(textureSize({}, {}){}))", sampler, lod,
1357 GetSwizzle(meta->element) + "))"; 1373 GetSwizzle(meta->element));
1358 case 2: 1374 case 2:
1359 return "0"; 1375 return "0";
1360 case 3: 1376 case 3:
1361 return "itof(textureQueryLevels(" + sampler + "))"; 1377 return fmt::format("itof(textureQueryLevels({}))", sampler);
1362 } 1378 }
1363 UNREACHABLE(); 1379 UNREACHABLE();
1364 return "0"; 1380 return "0";
@@ -1369,8 +1385,9 @@ private:
1369 ASSERT(meta); 1385 ASSERT(meta);
1370 1386
1371 if (meta->element < 2) { 1387 if (meta->element < 2) {
1372 return "itof(int((" + GenerateTexture(operation, "QueryLod", {}) + " * vec2(256))" + 1388 return fmt::format("itof(int(({} * vec2(256)){}))",
1373 GetSwizzle(meta->element) + "))"; 1389 GenerateTexture(operation, "QueryLod", {}),
1390 GetSwizzle(meta->element));
1374 } 1391 }
1375 return "0"; 1392 return "0";
1376 } 1393 }
@@ -1409,7 +1426,7 @@ private:
1409 const auto target = std::get_if<ImmediateNode>(operation[0]); 1426 const auto target = std::get_if<ImmediateNode>(operation[0]);
1410 UNIMPLEMENTED_IF(!target); 1427 UNIMPLEMENTED_IF(!target);
1411 1428
1412 code.AddLine(fmt::format("jmp_to = 0x{:x}u;", target->GetValue())); 1429 code.AddLine("jmp_to = 0x{:x}u;", target->GetValue());
1413 code.AddLine("break;"); 1430 code.AddLine("break;");
1414 return {}; 1431 return {};
1415 } 1432 }
@@ -1418,7 +1435,7 @@ private:
1418 const auto target = std::get_if<ImmediateNode>(operation[0]); 1435 const auto target = std::get_if<ImmediateNode>(operation[0]);
1419 UNIMPLEMENTED_IF(!target); 1436 UNIMPLEMENTED_IF(!target);
1420 1437
1421 code.AddLine(fmt::format("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue())); 1438 code.AddLine("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue());
1422 return {}; 1439 return {};
1423 } 1440 }
1424 1441
@@ -1455,8 +1472,7 @@ private:
1455 header.ps.IsColorComponentOutputEnabled(render_target, 1) || 1472 header.ps.IsColorComponentOutputEnabled(render_target, 1) ||
1456 header.ps.IsColorComponentOutputEnabled(render_target, 2) || 1473 header.ps.IsColorComponentOutputEnabled(render_target, 2) ||
1457 header.ps.IsColorComponentOutputEnabled(render_target, 3)) { 1474 header.ps.IsColorComponentOutputEnabled(render_target, 3)) {
1458 code.AddLine( 1475 code.AddLine("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg));
1459 fmt::format("if (!AlphaFunc({})) discard;", SafeGetRegister(current_reg)));
1460 current_reg += 4; 1476 current_reg += 4;
1461 } 1477 }
1462 } 1478 }
@@ -1470,8 +1486,8 @@ private:
1470 // TODO(Subv): Figure out how dual-source blending is configured in the Switch. 1486 // TODO(Subv): Figure out how dual-source blending is configured in the Switch.
1471 for (u32 component = 0; component < 4; ++component) { 1487 for (u32 component = 0; component < 4; ++component) {
1472 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) { 1488 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) {
1473 code.AddLine(fmt::format("FragColor{}[{}] = {};", render_target, component, 1489 code.AddLine("FragColor{}[{}] = {};", render_target, component,
1474 SafeGetRegister(current_reg))); 1490 SafeGetRegister(current_reg));
1475 ++current_reg; 1491 ++current_reg;
1476 } 1492 }
1477 } 1493 }
@@ -1708,7 +1724,7 @@ private:
1708 const auto index = static_cast<u32>(flag); 1724 const auto index = static_cast<u32>(flag);
1709 ASSERT(index < static_cast<u32>(InternalFlag::Amount)); 1725 ASSERT(index < static_cast<u32>(InternalFlag::Amount));
1710 1726
1711 return std::string(InternalFlagNames[index]) + '_' + suffix; 1727 return fmt::format("{}_{}", InternalFlagNames[index], suffix);
1712 } 1728 }
1713 1729
1714 std::string GetSampler(const Sampler& sampler) const { 1730 std::string GetSampler(const Sampler& sampler) const {
@@ -1716,7 +1732,7 @@ private:
1716 } 1732 }
1717 1733
1718 std::string GetDeclarationWithSuffix(u32 index, const std::string& name) const { 1734 std::string GetDeclarationWithSuffix(u32 index, const std::string& name) const {
1719 return name + '_' + std::to_string(index) + '_' + suffix; 1735 return fmt::format("{}_{}_{}", name, index, suffix);
1720 } 1736 }
1721 1737
1722 u32 GetNumPhysicalInputAttributes() const { 1738 u32 GetNumPhysicalInputAttributes() const {