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).
This commit is contained in:
		
							parent
							
								
									3dcaa84ba4
								
							
						
					
					
						commit
						4d711dface
					
				@ -23,6 +23,7 @@
 | 
				
			|||||||
#include "video_core/shader/ast.h"
 | 
					#include "video_core/shader/ast.h"
 | 
				
			||||||
#include "video_core/shader/node.h"
 | 
					#include "video_core/shader/node.h"
 | 
				
			||||||
#include "video_core/shader/shader_ir.h"
 | 
					#include "video_core/shader/shader_ir.h"
 | 
				
			||||||
 | 
					#include "video_core/shader/transform_feedback.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace OpenGL {
 | 
					namespace OpenGL {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -36,6 +37,7 @@ using Tegra::Shader::IpaInterpMode;
 | 
				
			|||||||
using Tegra::Shader::IpaMode;
 | 
					using Tegra::Shader::IpaMode;
 | 
				
			||||||
using Tegra::Shader::IpaSampleMode;
 | 
					using Tegra::Shader::IpaSampleMode;
 | 
				
			||||||
using Tegra::Shader::Register;
 | 
					using Tegra::Shader::Register;
 | 
				
			||||||
 | 
					using VideoCommon::Shader::BuildTransformFeedback;
 | 
				
			||||||
using VideoCommon::Shader::Registry;
 | 
					using VideoCommon::Shader::Registry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
using namespace std::string_literals;
 | 
					using namespace std::string_literals;
 | 
				
			||||||
@ -49,6 +51,11 @@ class ExprDecompiler;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat };
 | 
					enum class Type { Void, Bool, Bool2, Float, Int, Uint, HalfFloat };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr std::array FLOAT_TYPES{"float", "vec2", "vec3", "vec4"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					constexpr std::string_view INPUT_ATTRIBUTE_NAME = "in_attr";
 | 
				
			||||||
 | 
					constexpr std::string_view OUTPUT_ATTRIBUTE_NAME = "out_attr";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TextureOffset {};
 | 
					struct TextureOffset {};
 | 
				
			||||||
struct TextureDerivates {};
 | 
					struct TextureDerivates {};
 | 
				
			||||||
using TextureArgument = std::pair<Type, Node>;
 | 
					using TextureArgument = std::pair<Type, Node>;
 | 
				
			||||||
@ -390,12 +397,19 @@ std::string FlowStackTopName(MetaStackClass stack) {
 | 
				
			|||||||
    return stage == ShaderType::Vertex;
 | 
					    return stage == ShaderType::Vertex;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct GenericVaryingDescription {
 | 
				
			||||||
 | 
					    std::string name;
 | 
				
			||||||
 | 
					    u8 first_element = 0;
 | 
				
			||||||
 | 
					    bool is_scalar = false;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GLSLDecompiler final {
 | 
					class GLSLDecompiler final {
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry,
 | 
					    explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, const Registry& registry,
 | 
				
			||||||
                            ShaderType stage, std::string_view identifier, std::string_view suffix)
 | 
					                            ShaderType stage, std::string_view identifier, std::string_view suffix)
 | 
				
			||||||
        : device{device}, ir{ir}, registry{registry}, stage{stage},
 | 
					        : device{device}, ir{ir}, registry{registry}, stage{stage},
 | 
				
			||||||
          identifier{identifier}, suffix{suffix}, header{ir.GetHeader()} {}
 | 
					          identifier{identifier}, suffix{suffix}, header{ir.GetHeader()},
 | 
				
			||||||
 | 
					          transform_feedback{BuildTransformFeedback(registry.GetGraphicsInfo())} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void Decompile() {
 | 
					    void Decompile() {
 | 
				
			||||||
        DeclareHeader();
 | 
					        DeclareHeader();
 | 
				
			||||||
@ -403,17 +417,17 @@ public:
 | 
				
			|||||||
        DeclareGeometry();
 | 
					        DeclareGeometry();
 | 
				
			||||||
        DeclareFragment();
 | 
					        DeclareFragment();
 | 
				
			||||||
        DeclareCompute();
 | 
					        DeclareCompute();
 | 
				
			||||||
        DeclareRegisters();
 | 
					 | 
				
			||||||
        DeclareCustomVariables();
 | 
					 | 
				
			||||||
        DeclarePredicates();
 | 
					 | 
				
			||||||
        DeclareLocalMemory();
 | 
					 | 
				
			||||||
        DeclareInternalFlags();
 | 
					 | 
				
			||||||
        DeclareInputAttributes();
 | 
					        DeclareInputAttributes();
 | 
				
			||||||
        DeclareOutputAttributes();
 | 
					        DeclareOutputAttributes();
 | 
				
			||||||
        DeclareConstantBuffers();
 | 
					 | 
				
			||||||
        DeclareGlobalMemory();
 | 
					 | 
				
			||||||
        DeclareSamplers();
 | 
					 | 
				
			||||||
        DeclareImages();
 | 
					        DeclareImages();
 | 
				
			||||||
 | 
					        DeclareSamplers();
 | 
				
			||||||
 | 
					        DeclareGlobalMemory();
 | 
				
			||||||
 | 
					        DeclareConstantBuffers();
 | 
				
			||||||
 | 
					        DeclareLocalMemory();
 | 
				
			||||||
 | 
					        DeclareRegisters();
 | 
				
			||||||
 | 
					        DeclarePredicates();
 | 
				
			||||||
 | 
					        DeclareInternalFlags();
 | 
				
			||||||
 | 
					        DeclareCustomVariables();
 | 
				
			||||||
        DeclarePhysicalAttributeReader();
 | 
					        DeclarePhysicalAttributeReader();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        code.AddLine("void main() {{");
 | 
					        code.AddLine("void main() {{");
 | 
				
			||||||
@ -485,7 +499,7 @@ private:
 | 
				
			|||||||
        if (!identifier.empty()) {
 | 
					        if (!identifier.empty()) {
 | 
				
			||||||
            code.AddLine("// {}", identifier);
 | 
					            code.AddLine("// {}", identifier);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        code.AddLine("#version 430 core");
 | 
					        code.AddLine("#version 440 core");
 | 
				
			||||||
        code.AddLine("#extension GL_ARB_separate_shader_objects : enable");
 | 
					        code.AddLine("#extension GL_ARB_separate_shader_objects : enable");
 | 
				
			||||||
        if (device.HasShaderBallot()) {
 | 
					        if (device.HasShaderBallot()) {
 | 
				
			||||||
            code.AddLine("#extension GL_ARB_shader_ballot : require");
 | 
					            code.AddLine("#extension GL_ARB_shader_ballot : require");
 | 
				
			||||||
@ -570,7 +584,13 @@ private:
 | 
				
			|||||||
        code.AddLine("out gl_PerVertex {{");
 | 
					        code.AddLine("out gl_PerVertex {{");
 | 
				
			||||||
        ++code.scope;
 | 
					        ++code.scope;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        code.AddLine("vec4 gl_Position;");
 | 
					        auto pos_xfb = GetTransformFeedbackDecoration(Attribute::Index::Position);
 | 
				
			||||||
 | 
					        if (!pos_xfb.empty()) {
 | 
				
			||||||
 | 
					            pos_xfb = fmt::format("layout ({}) ", pos_xfb);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const char* pos_type =
 | 
				
			||||||
 | 
					            FLOAT_TYPES.at(GetNumComponents(Attribute::Index::Position).value_or(4) - 1);
 | 
				
			||||||
 | 
					        code.AddLine("{}{} gl_Position;", pos_xfb, pos_type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const auto attribute : ir.GetOutputAttributes()) {
 | 
					        for (const auto attribute : ir.GetOutputAttributes()) {
 | 
				
			||||||
            if (attribute == Attribute::Index::ClipDistances0123 ||
 | 
					            if (attribute == Attribute::Index::ClipDistances0123 ||
 | 
				
			||||||
@ -703,7 +723,7 @@ private:
 | 
				
			|||||||
    void DeclareInputAttribute(Attribute::Index index, bool skip_unused) {
 | 
					    void DeclareInputAttribute(Attribute::Index index, bool skip_unused) {
 | 
				
			||||||
        const u32 location{GetGenericAttributeIndex(index)};
 | 
					        const u32 location{GetGenericAttributeIndex(index)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string name{GetInputAttribute(index)};
 | 
					        std::string name{GetGenericInputAttribute(index)};
 | 
				
			||||||
        if (stage == ShaderType::Geometry) {
 | 
					        if (stage == ShaderType::Geometry) {
 | 
				
			||||||
            name = "gs_" + name + "[]";
 | 
					            name = "gs_" + name + "[]";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -740,9 +760,58 @@ private:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::optional<std::size_t> GetNumComponents(Attribute::Index index, u8 element = 0) const {
 | 
				
			||||||
 | 
					        const u8 location = static_cast<u8>(index) * 4 + element;
 | 
				
			||||||
 | 
					        const auto it = transform_feedback.find(location);
 | 
				
			||||||
 | 
					        if (it == transform_feedback.end()) {
 | 
				
			||||||
 | 
					            return {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return it->second.components;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::string GetTransformFeedbackDecoration(Attribute::Index index, u8 element = 0) const {
 | 
				
			||||||
 | 
					        const u8 location = static_cast<u8>(index) * 4 + element;
 | 
				
			||||||
 | 
					        const auto it = transform_feedback.find(location);
 | 
				
			||||||
 | 
					        if (it == transform_feedback.end()) {
 | 
				
			||||||
 | 
					            return {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const VaryingTFB& tfb = it->second;
 | 
				
			||||||
 | 
					        return fmt::format("xfb_buffer = {}, xfb_offset = {}", tfb.buffer, tfb.offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DeclareOutputAttribute(Attribute::Index index) {
 | 
					    void DeclareOutputAttribute(Attribute::Index index) {
 | 
				
			||||||
        const u32 location{GetGenericAttributeIndex(index)};
 | 
					        static constexpr std::string_view swizzle = "xyzw";
 | 
				
			||||||
        code.AddLine("layout (location = {}) out vec4 {};", location, GetOutputAttribute(index));
 | 
					        u8 element = 0;
 | 
				
			||||||
 | 
					        while (element < 4) {
 | 
				
			||||||
 | 
					            auto xfb = GetTransformFeedbackDecoration(index, element);
 | 
				
			||||||
 | 
					            if (!xfb.empty()) {
 | 
				
			||||||
 | 
					                xfb = fmt::format(", {}", xfb);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const std::size_t remainder = 4 - element;
 | 
				
			||||||
 | 
					            const std::size_t num_components = GetNumComponents(index, element).value_or(remainder);
 | 
				
			||||||
 | 
					            const char* const type = FLOAT_TYPES.at(num_components - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            const u32 location = GetGenericAttributeIndex(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            GenericVaryingDescription description;
 | 
				
			||||||
 | 
					            description.first_element = static_cast<u8>(element);
 | 
				
			||||||
 | 
					            description.is_scalar = num_components == 1;
 | 
				
			||||||
 | 
					            description.name = AppendSuffix(location, OUTPUT_ATTRIBUTE_NAME);
 | 
				
			||||||
 | 
					            if (element != 0 || num_components != 4) {
 | 
				
			||||||
 | 
					                const std::string_view name_swizzle = swizzle.substr(element, num_components);
 | 
				
			||||||
 | 
					                description.name = fmt::format("{}_{}", description.name, name_swizzle);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            for (std::size_t i = 0; i < num_components; ++i) {
 | 
				
			||||||
 | 
					                const u8 offset = static_cast<u8>(location * 4 + element + i);
 | 
				
			||||||
 | 
					                varying_description.insert({offset, description});
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            code.AddLine("layout (location = {}, component = {}{}) out {} {};", location, element,
 | 
				
			||||||
 | 
					                         xfb, type, description.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            element += static_cast<u8>(num_components);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void DeclareConstantBuffers() {
 | 
					    void DeclareConstantBuffers() {
 | 
				
			||||||
@ -1095,7 +1164,7 @@ private:
 | 
				
			|||||||
            return {"0", Type::Int};
 | 
					            return {"0", Type::Int};
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            if (IsGenericAttribute(attribute)) {
 | 
					            if (IsGenericAttribute(attribute)) {
 | 
				
			||||||
                return {GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element),
 | 
					                return {GeometryPass(GetGenericInputAttribute(attribute)) + GetSwizzle(element),
 | 
				
			||||||
                        Type::Float};
 | 
					                        Type::Float};
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
@ -1164,8 +1233,7 @@ private:
 | 
				
			|||||||
            return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}};
 | 
					            return {{fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4), Type::Float}};
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            if (IsGenericAttribute(attribute)) {
 | 
					            if (IsGenericAttribute(attribute)) {
 | 
				
			||||||
                return {
 | 
					                return {{GetGenericOutputAttribute(attribute, abuf->GetElement()), Type::Float}};
 | 
				
			||||||
                    {GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), Type::Float}};
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
 | 
					            UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
 | 
				
			||||||
            return {};
 | 
					            return {};
 | 
				
			||||||
@ -2376,27 +2444,34 @@ private:
 | 
				
			|||||||
    static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
 | 
					    static_assert(operation_decompilers.size() == static_cast<std::size_t>(OperationCode::Amount));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetRegister(u32 index) const {
 | 
					    std::string GetRegister(u32 index) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(index, "gpr");
 | 
					        return AppendSuffix(index, "gpr");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetCustomVariable(u32 index) const {
 | 
					    std::string GetCustomVariable(u32 index) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(index, "custom_var");
 | 
					        return AppendSuffix(index, "custom_var");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetPredicate(Tegra::Shader::Pred pred) const {
 | 
					    std::string GetPredicate(Tegra::Shader::Pred pred) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(static_cast<u32>(pred), "pred");
 | 
					        return AppendSuffix(static_cast<u32>(pred), "pred");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetInputAttribute(Attribute::Index attribute) const {
 | 
					    std::string GetGenericInputAttribute(Attribute::Index attribute) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(GetGenericAttributeIndex(attribute), "input_attr");
 | 
					        return AppendSuffix(GetGenericAttributeIndex(attribute), INPUT_ATTRIBUTE_NAME);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetOutputAttribute(Attribute::Index attribute) const {
 | 
					    std::unordered_map<u8, GenericVaryingDescription> varying_description;
 | 
				
			||||||
        return GetDeclarationWithSuffix(GetGenericAttributeIndex(attribute), "output_attr");
 | 
					
 | 
				
			||||||
 | 
					    std::string GetGenericOutputAttribute(Attribute::Index attribute, std::size_t element) const {
 | 
				
			||||||
 | 
					        const u8 offset = static_cast<u8>(GetGenericAttributeIndex(attribute) * 4 + element);
 | 
				
			||||||
 | 
					        const auto& description = varying_description.at(offset);
 | 
				
			||||||
 | 
					        if (description.is_scalar) {
 | 
				
			||||||
 | 
					            return description.name;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return fmt::format("{}[{}]", description.name, element - description.first_element);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetConstBuffer(u32 index) const {
 | 
					    std::string GetConstBuffer(u32 index) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(index, "cbuf");
 | 
					        return AppendSuffix(index, "cbuf");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetGlobalMemory(const GlobalMemoryBase& descriptor) const {
 | 
					    std::string GetGlobalMemory(const GlobalMemoryBase& descriptor) const {
 | 
				
			||||||
@ -2409,7 +2484,7 @@ private:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetConstBufferBlock(u32 index) const {
 | 
					    std::string GetConstBufferBlock(u32 index) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(index, "cbuf_block");
 | 
					        return AppendSuffix(index, "cbuf_block");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetLocalMemory() const {
 | 
					    std::string GetLocalMemory() const {
 | 
				
			||||||
@ -2434,14 +2509,14 @@ private:
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetSampler(const Sampler& sampler) const {
 | 
					    std::string GetSampler(const Sampler& sampler) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(static_cast<u32>(sampler.GetIndex()), "sampler");
 | 
					        return AppendSuffix(static_cast<u32>(sampler.GetIndex()), "sampler");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetImage(const Image& image) const {
 | 
					    std::string GetImage(const Image& image) const {
 | 
				
			||||||
        return GetDeclarationWithSuffix(static_cast<u32>(image.GetIndex()), "image");
 | 
					        return AppendSuffix(static_cast<u32>(image.GetIndex()), "image");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::string GetDeclarationWithSuffix(u32 index, std::string_view name) const {
 | 
					    std::string AppendSuffix(u32 index, std::string_view name) const {
 | 
				
			||||||
        if (suffix.empty()) {
 | 
					        if (suffix.empty()) {
 | 
				
			||||||
            return fmt::format("{}{}", name, index);
 | 
					            return fmt::format("{}{}", name, index);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@ -2477,6 +2552,7 @@ private:
 | 
				
			|||||||
    const std::string_view identifier;
 | 
					    const std::string_view identifier;
 | 
				
			||||||
    const std::string_view suffix;
 | 
					    const std::string_view suffix;
 | 
				
			||||||
    const Header header;
 | 
					    const Header header;
 | 
				
			||||||
 | 
					    const std::unordered_map<u8, VaryingTFB> transform_feedback;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ShaderWriter code;
 | 
					    ShaderWriter code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user