diff options
| author | 2020-03-02 18:55:39 -0300 | |
|---|---|---|
| committer | 2020-03-13 18:33:04 -0300 | |
| commit | 4d711dface5dfc76d5ae0d62c635ec9ba6bd4293 (patch) | |
| tree | d17ce1cda84d67e53e3ced539a2de94c5ad7c24d /src | |
| parent | shader/transform_feedback: Add host API friendly TFB builder (diff) | |
| download | yuzu-4d711dface5dfc76d5ae0d62c635ec9ba6bd4293.tar.gz yuzu-4d711dface5dfc76d5ae0d62c635ec9ba6bd4293.tar.xz yuzu-4d711dface5dfc76d5ae0d62c635ec9ba6bd4293.zip | |
gl_shader_decompiler: Decorate output attributes with XFB layout
We sometimes have to slice attributes in different parts. This is needed
for example in instances where the game feedbacks 3 components but
writes 4 from the shader (something that is possible with
GL_NV_transform_feedback).
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 134 |
1 files changed, 105 insertions, 29 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 19d6f3dcb..021edf1f6 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "video_core/shader/ast.h" | 23 | #include "video_core/shader/ast.h" |
| 24 | #include "video_core/shader/node.h" | 24 | #include "video_core/shader/node.h" |
| 25 | #include "video_core/shader/shader_ir.h" | 25 | #include "video_core/shader/shader_ir.h" |
| 26 | #include "video_core/shader/transform_feedback.h" | ||
| 26 | 27 | ||
| 27 | namespace OpenGL { | 28 | namespace OpenGL { |
| 28 | 29 | ||
| @@ -36,6 +37,7 @@ using Tegra::Shader::IpaInterpMode; | |||
| 36 | using Tegra::Shader::IpaMode; | 37 | using Tegra::Shader::IpaMode; |
| 37 | using Tegra::Shader::IpaSampleMode; | 38 | using Tegra::Shader::IpaSampleMode; |
| 38 | using Tegra::Shader::Register; | 39 | using Tegra::Shader::Register; |
| 40 | using VideoCommon::Shader::BuildTransformFeedback; | ||
| 39 | using VideoCommon::Shader::Registry; | 41 | using VideoCommon::Shader::Registry; |
| 40 | 42 | ||
| 41 | using namespace std::string_literals; | 43 | using namespace std::string_literals; |
| @@ -49,6 +51,11 @@ class ExprDecompiler; | |||
| 49 | 51 | ||
| 50 | enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat }; | 52 | enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat }; |
| 51 | 53 | ||
| 54 | constexpr std::array FLOAT_TYPES{"float", "vec2", "vec3", "vec4"}; | ||
| 55 | |||
| 56 | constexpr std::string_view INPUT_ATTRIBUTE_NAME = "in_attr"; | ||
| 57 | constexpr std::string_view OUTPUT_ATTRIBUTE_NAME = "out_attr"; | ||
| 58 | |||
| 52 | struct TextureOffset {}; | 59 | struct TextureOffset {}; |
| 53 | struct TextureDerivates {}; | 60 | struct TextureDerivates {}; |
| 54 | using TextureArgument = std::pair<Type, Node>; | 61 | using TextureArgument = std::pair<Type, Node>; |
| @@ -390,12 +397,19 @@ std::string FlowStackTopName(MetaStackClass stack) { | |||
| 390 | return stage == ShaderType::Vertex; | 397 | return stage == ShaderType::Vertex; |
| 391 | } | 398 | } |
| 392 | 399 | ||
| 400 | struct GenericVaryingDescription { | ||
| 401 | std::string name; | ||
| 402 | u8 first_element = 0; | ||
| 403 | bool is_scalar = false; | ||
| 404 | }; | ||
| 405 | |||
| 393 | class GLSLDecompiler final { | 406 | class GLSLDecompiler final { |
| 394 | public: | 407 | public: |
| 395 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, | 408 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry, |
| 396 | ShaderType stage, std::string_view identifier, std::string_view suffix) | 409 | ShaderType stage, std::string_view identifier, std::string_view suffix) |
| 397 | : device{device}, ir{ir}, registry{registry}, stage{stage}, | 410 | : device{device}, ir{ir}, registry{registry}, stage{stage}, |
| 398 | identifier{identifier}, suffix{suffix}, header{ir.GetHeader()} {} | 411 | identifier{identifier}, suffix{suffix}, header{ir.GetHeader()}, |
| 412 | transform_feedback{BuildTransformFeedback(registry.GetGraphicsInfo())} {} | ||
| 399 | 413 | ||
| 400 | void Decompile() { | 414 | void Decompile() { |
| 401 | DeclareHeader(); | 415 | DeclareHeader(); |
| @@ -403,17 +417,17 @@ public: | |||
| 403 | DeclareGeometry(); | 417 | DeclareGeometry(); |
| 404 | DeclareFragment(); | 418 | DeclareFragment(); |
| 405 | DeclareCompute(); | 419 | DeclareCompute(); |
| 406 | DeclareRegisters(); | ||
| 407 | DeclareCustomVariables(); | ||
| 408 | DeclarePredicates(); | ||
| 409 | DeclareLocalMemory(); | ||
| 410 | DeclareInternalFlags(); | ||
| 411 | DeclareInputAttributes(); | 420 | DeclareInputAttributes(); |
| 412 | DeclareOutputAttributes(); | 421 | DeclareOutputAttributes(); |
| 413 | DeclareConstantBuffers(); | ||
| 414 | DeclareGlobalMemory(); | ||
| 415 | DeclareSamplers(); | ||
| 416 | DeclareImages(); | 422 | DeclareImages(); |
| 423 | DeclareSamplers(); | ||
| 424 | DeclareGlobalMemory(); | ||
| 425 | DeclareConstantBuffers(); | ||
| 426 | DeclareLocalMemory(); | ||
| 427 | DeclareRegisters(); | ||
| 428 | DeclarePredicates(); | ||
| 429 | DeclareInternalFlags(); | ||
| 430 | DeclareCustomVariables(); | ||
| 417 | DeclarePhysicalAttributeReader(); | 431 | DeclarePhysicalAttributeReader(); |
| 418 | 432 | ||
| 419 | code.AddLine("void main() {{"); | 433 | code.AddLine("void main() {{"); |
| @@ -485,7 +499,7 @@ private: | |||
| 485 | if (!identifier.empty()) { | 499 | if (!identifier.empty()) { |
| 486 | code.AddLine("// {}", identifier); | 500 | code.AddLine("// {}", identifier); |
| 487 | } | 501 | } |
| 488 | code.AddLine("#version 430 core"); | 502 | code.AddLine("#version 440 core"); |
| 489 | code.AddLine("#extension GL_ARB_separate_shader_objects : enable"); | 503 | code.AddLine("#extension GL_ARB_separate_shader_objects : enable"); |
| 490 | if (device.HasShaderBallot()) { | 504 | if (device.HasShaderBallot()) { |
| 491 | code.AddLine("#extension GL_ARB_shader_ballot : require"); | 505 | code.AddLine("#extension GL_ARB_shader_ballot : require"); |
| @@ -570,7 +584,13 @@ private: | |||
| 570 | code.AddLine("out gl_PerVertex {{"); | 584 | code.AddLine("out gl_PerVertex {{"); |
| 571 | ++code.scope; | 585 | ++code.scope; |
| 572 | 586 | ||
| 573 | code.AddLine("vec4 gl_Position;"); | 587 | auto pos_xfb = GetTransformFeedbackDecoration(Attribute::Index::Position); |
| 588 | if (!pos_xfb.empty()) { | ||
| 589 | pos_xfb = fmt::format("layout ({}) ", pos_xfb); | ||
| 590 | } | ||
| 591 | const char* pos_type = | ||
| 592 | FLOAT_TYPES.at(GetNumComponents(Attribute::Index::Position).value_or(4) - 1); | ||
| 593 | code.AddLine("{}{} gl_Position;", pos_xfb, pos_type); | ||
| 574 | 594 | ||
| 575 | for (const auto attribute : ir.GetOutputAttributes()) { | 595 | for (const auto attribute : ir.GetOutputAttributes()) { |
| 576 | if (attribute == Attribute::Index::ClipDistances0123 || | 596 | if (attribute == Attribute::Index::ClipDistances0123 || |
| @@ -703,7 +723,7 @@ private: | |||
| 703 | void DeclareInputAttribute(Attribute::Index index, bool skip_unused) { | 723 | void DeclareInputAttribute(Attribute::Index index, bool skip_unused) { |
| 704 | const u32 location{GetGenericAttributeIndex(index)}; | 724 | const u32 location{GetGenericAttributeIndex(index)}; |
| 705 | 725 | ||
| 706 | std::string name{GetInputAttribute(index)}; | 726 | std::string name{GetGenericInputAttribute(index)}; |
| 707 | if (stage == ShaderType::Geometry) { | 727 | if (stage == ShaderType::Geometry) { |
| 708 | name = "gs_" + name + "[]"; | 728 | name = "gs_" + name + "[]"; |
| 709 | } | 729 | } |
| @@ -740,9 +760,58 @@ private: | |||
| 740 | } | 760 | } |
| 741 | } | 761 | } |
| 742 | 762 | ||
| 763 | std::optional<std::size_t> GetNumComponents(Attribute::Index index, u8 element = 0) const { | ||
| 764 | const u8 location = static_cast<u8>(index) * 4 + element; | ||
| 765 | const auto it = transform_feedback.find(location); | ||
| 766 | if (it == transform_feedback.end()) { | ||
| 767 | return {}; | ||
| 768 | } | ||
| 769 | return it->second.components; | ||
| 770 | } | ||
| 771 | |||
| 772 | std::string GetTransformFeedbackDecoration(Attribute::Index index, u8 element = 0) const { | ||
| 773 | const u8 location = static_cast<u8>(index) * 4 + element; | ||
| 774 | const auto it = transform_feedback.find(location); | ||
| 775 | if (it == transform_feedback.end()) { | ||
| 776 | return {}; | ||
| 777 | } | ||
| 778 | |||
| 779 | const VaryingTFB& tfb = it->second; | ||
| 780 | return fmt::format("xfb_buffer = {}, xfb_offset = {}", tfb.buffer, tfb.offset); | ||
| 781 | } | ||
| 782 | |||
| 743 | void DeclareOutputAttribute(Attribute::Index index) { | 783 | void DeclareOutputAttribute(Attribute::Index index) { |
| 744 | const u32 location{GetGenericAttributeIndex(index)}; | 784 | static constexpr std::string_view swizzle = "xyzw"; |
| 745 | code.AddLine("layout (location = {}) out vec4 {};", location, GetOutputAttribute(index)); | 785 | u8 element = 0; |
| 786 | while (element < 4) { | ||
| 787 | auto xfb = GetTransformFeedbackDecoration(index, element); | ||
| 788 | if (!xfb.empty()) { | ||
| 789 | xfb = fmt::format(", {}", xfb); | ||
| 790 | } | ||
| 791 | const std::size_t remainder = 4 - element; | ||
| 792 | const std::size_t num_components = GetNumComponents(index, element).value_or(remainder); | ||
| 793 | const char* const type = FLOAT_TYPES.at(num_components - 1); | ||
| 794 | |||
| 795 | const u32 location = GetGenericAttributeIndex(index); | ||
| 796 | |||
| 797 | GenericVaryingDescription description; | ||
| 798 | description.first_element = static_cast<u8>(element); | ||
| 799 | description.is_scalar = num_components == 1; | ||
| 800 | description.name = AppendSuffix(location, OUTPUT_ATTRIBUTE_NAME); | ||
| 801 | if (element != 0 || num_components != 4) { | ||
| 802 | const std::string_view name_swizzle = swizzle.substr(element, num_components); | ||
| 803 | description.name = fmt::format("{}_{}", description.name, name_swizzle); | ||
| 804 | } | ||
| 805 | for (std::size_t i = 0; i < num_components; ++i) { | ||
| 806 | const u8 offset = static_cast<u8>(location * 4 + element + i); | ||
| 807 | varying_description.insert({offset, description}); | ||
| 808 | } | ||
| 809 | |||
| 810 | code.AddLine("layout (location = {}, component = {}{}) out {} {};", location, element, | ||
| 811 | xfb, type, description.name); | ||
| 812 | |||
| 813 | element += static_cast<u8>(num_components); | ||
| 814 | } | ||
| 746 | } | 815 | } |
| 747 | 816 | ||
| 748 | void DeclareConstantBuffers() { | 817 | void DeclareConstantBuffers() { |
| @@ -1095,7 +1164,7 @@ private: | |||
| 1095 | return {"0", Type::Int}; | 1164 | return {"0", Type::Int}; |
| 1096 | default: | 1165 | default: |
| 1097 | if (IsGenericAttribute(attribute)) { | 1166 | if (IsGenericAttribute(attribute)) { |
| 1098 | return {GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element), | 1167 | return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element), |
| 1099 | Type::Float}; | 1168 | Type::Float}; |
| 1100 | } | 1169 | } |
| 1101 | break; | 1170 | break; |
| @@ -1164,8 +1233,7 @@ private: | |||
| 1164 | return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}}; | 1233 | return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}}; |
| 1165 | default: | 1234 | default: |
| 1166 | if (IsGenericAttribute(attribute)) { | 1235 | if (IsGenericAttribute(attribute)) { |
| 1167 | return { | 1236 | return {{GetGenericOutputAttribute(attribute, abuf->GetElement()), Type::Float}}; |
| 1168 | {GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), Type::Float}}; | ||
| 1169 | } | 1237 | } |
| 1170 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); | 1238 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute)); |
| 1171 | return {}; | 1239 | return {}; |
| @@ -2376,27 +2444,34 @@ private: | |||
| 2376 | static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); | 2444 | static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount)); |
| 2377 | 2445 | ||
| 2378 | std::string GetRegister(u32 index) const { | 2446 | std::string GetRegister(u32 index) const { |
| 2379 | return GetDeclarationWithSuffix(index, "gpr"); | 2447 | return AppendSuffix(index, "gpr"); |
| 2380 | } | 2448 | } |
| 2381 | 2449 | ||
| 2382 | std::string GetCustomVariable(u32 index) const { | 2450 | std::string GetCustomVariable(u32 index) const { |
| 2383 | return GetDeclarationWithSuffix(index, "custom_var"); | 2451 | return AppendSuffix(index, "custom_var"); |
| 2384 | } | 2452 | } |
| 2385 | 2453 | ||
| 2386 | std::string GetPredicate(Tegra::Shader::Pred pred) const { | 2454 | std::string GetPredicate(Tegra::Shader::Pred pred) const { |
| 2387 | return GetDeclarationWithSuffix(static_cast<u32>(pred), "pred"); | 2455 | return AppendSuffix(static_cast<u32>(pred), "pred"); |
| 2388 | } | 2456 | } |
| 2389 | 2457 | ||
| 2390 | std::string GetInputAttribute(Attribute::Index attribute) const { | 2458 | std::string GetGenericInputAttribute(Attribute::Index attribute) const { |
| 2391 | return GetDeclarationWithSuffix(GetGenericAttributeIndex(attribute), "input_attr"); | 2459 | return AppendSuffix(GetGenericAttributeIndex(attribute), INPUT_ATTRIBUTE_NAME); |
| 2392 | } | 2460 | } |
| 2393 | 2461 | ||
| 2394 | std::string GetOutputAttribute(Attribute::Index attribute) const { | 2462 | std::unordered_map<u8, GenericVaryingDescription> varying_description; |
| 2395 | return GetDeclarationWithSuffix(GetGenericAttributeIndex(attribute), "output_attr"); | 2463 | |
| 2464 | std::string GetGenericOutputAttribute(Attribute::Index attribute, std::size_t element) const { | ||
| 2465 | const u8 offset = static_cast<u8>(GetGenericAttributeIndex(attribute) * 4 + element); | ||
| 2466 | const auto& description = varying_description.at(offset); | ||
| 2467 | if (description.is_scalar) { | ||
| 2468 | return description.name; | ||
| 2469 | } | ||
| 2470 | return fmt::format("{}[{}]", description.name, element - description.first_element); | ||
| 2396 | } | 2471 | } |
| 2397 | 2472 | ||
| 2398 | std::string GetConstBuffer(u32 index) const { | 2473 | std::string GetConstBuffer(u32 index) const { |
| 2399 | return GetDeclarationWithSuffix(index, "cbuf"); | 2474 | return AppendSuffix(index, "cbuf"); |
| 2400 | } | 2475 | } |
| 2401 | 2476 | ||
| 2402 | std::string GetGlobalMemory(const GlobalMemoryBase& descriptor) const { | 2477 | std::string GetGlobalMemory(const GlobalMemoryBase& descriptor) const { |
| @@ -2409,7 +2484,7 @@ private: | |||
| 2409 | } | 2484 | } |
| 2410 | 2485 | ||
| 2411 | std::string GetConstBufferBlock(u32 index) const { | 2486 | std::string GetConstBufferBlock(u32 index) const { |
| 2412 | return GetDeclarationWithSuffix(index, "cbuf_block"); | 2487 | return AppendSuffix(index, "cbuf_block"); |
| 2413 | } | 2488 | } |
| 2414 | 2489 | ||
| 2415 | std::string GetLocalMemory() const { | 2490 | std::string GetLocalMemory() const { |
| @@ -2434,14 +2509,14 @@ private: | |||
| 2434 | } | 2509 | } |
| 2435 | 2510 | ||
| 2436 | std::string GetSampler(const Sampler& sampler) const { | 2511 | std::string GetSampler(const Sampler& sampler) const { |
| 2437 | return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler"); | 2512 | return AppendSuffix(static_cast<u32>(sampler.GetIndex()), "sampler"); |
| 2438 | } | 2513 | } |
| 2439 | 2514 | ||
| 2440 | std::string GetImage(const Image& image) const { | 2515 | std::string GetImage(const Image& image) const { |
| 2441 | return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image"); | 2516 | return AppendSuffix(static_cast<u32>(image.GetIndex()), "image"); |
| 2442 | } | 2517 | } |
| 2443 | 2518 | ||
| 2444 | std::string GetDeclarationWithSuffix(u32 index, std::string_view name) const { | 2519 | std::string AppendSuffix(u32 index, std::string_view name) const { |
| 2445 | if (suffix.empty()) { | 2520 | if (suffix.empty()) { |
| 2446 | return fmt::format("{}{}", name, index); | 2521 | return fmt::format("{}{}", name, index); |
| 2447 | } else { | 2522 | } else { |
| @@ -2477,6 +2552,7 @@ private: | |||
| 2477 | const std::string_view identifier; | 2552 | const std::string_view identifier; |
| 2478 | const std::string_view suffix; | 2553 | const std::string_view suffix; |
| 2479 | const Header header; | 2554 | const Header header; |
| 2555 | const std::unordered_map<u8, VaryingTFB> transform_feedback; | ||
| 2480 | 2556 | ||
| 2481 | ShaderWriter code; | 2557 | ShaderWriter code; |
| 2482 | 2558 | ||