diff options
| author | 2019-05-14 12:18:07 -0400 | |
|---|---|---|
| committer | 2019-05-20 14:14:44 -0400 | |
| commit | 784d2b6c3d0f3181a79732f576e4ec1ff147a858 (patch) | |
| tree | 0996bc3480e8f8b16101f60f805a5dc30c20f8d4 /src | |
| parent | gl_shader_decompiler: Add AddLine() overload that forwards to fmt (diff) | |
| download | yuzu-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.cpp | 288 |
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 { |